2013-08-13 15 views
5

Nieco pokrewne do my previous question hereUzyskaj obiekt wywołujący lub metody in D

Czy istnieje sposób, aby obiekt wywołujący od wewnątrz funkcji lub metody in D?

przykład:

class Foo 
{ 
    public void bar() 
    { 
     auto ci = whoCalledMe(); 
     // ci should be something that points me to baz.qux, _if_ baz.qux made the call 

    } 
} 

class Baz 
{ 
    void qux() 
    { 
     auto foo = new Foo(); 
     foo.bar(); 
    } 
} 

Pytania:

  1. Czy coś whoCalledMe istnieje? a jeśli tak, jak to się nazywa?
  2. jeśli coś istnieje, czy można go użyć w czasie kompilacji (w szablonie), a jeśli tak, to w jaki sposób?

Alternatywnie;

  1. Czy można uzyskać dostęp do stosu wywołań w czasie wykonywania? tak jak z php's debug_backtrace?
+0

Trochę ciężko, gdy połączenie można wykonać również z 'głównego' –

+0

@ratchetfreak: brakuje mi punktu Twojego komentarza? pamiętaj, że kod jest po to, aby wyjaśnić ogólną rzecz, a nie aby ograniczyć pytanie. – Kris

+0

Nie sądzę, że można osiągnąć to, co chcesz w dowolnym skompilowanym języku. W odniesieniu do pytania 2: w czasie kompilacji może być wielu wywołujących funkcję, można uzyskać listę wszystkich możliwych wywołujących (i nie sądzę, że jest to możliwe w D teraz). –

Odpowiedz

4

Nie jest możliwe bezpośrednie uzyskanie informacji o swoim "dzwoniącym". Możesz mieć trochę szczęścia z uzyskaniem adresu ze stosu wywołań, ale jest to operacja niskiego poziomu i zależy od rzeczy takich jak czy twój program został skompilowany z ramkami stosu. Po uzyskaniu adresu, możesz teoretycznie przekonwertować go na nazwę funkcji i numer linii, pod warunkiem, że symbole debugowania są dostępne dla pliku binarnego twojego programu, ale (znowu) jest to wysoce zależne od platformy i zależy od zestawu narzędzi używanego do kompilacji twojego programu .

Jako alternatywa, może się okazać się pomocne:

void callee(string file=__FILE__, int line=__LINE__, string func=__FUNCTION__)() 
{ 
    writefln("I was called by %s, which is in %s at line %d!", func, file, line); 
} 

void caller() 
{ 
    // Thanks to IFTI, we can call the function as usual. 
    callee(); 
} 

Należy jednak pamiętać, że nie można korzystać z tej sztuczki dla non-ostatecznych metod klasy, bo każde wywołanie funkcji wygeneruje nową instancję szablonu (i kompilator musi wcześniej znać adres wszystkich wirtualnych metod klasy).

+0

Znalazłem, a nawet użyłem __FILE__ i __LINE__ wcześniej, ale jeszcze nie wiedziałem o __FUNCTION__. czy jest więcej tych "magicznych stałych"? – Kris

+2

'__FUNCTION__' został niedawno dodany (https://github.com/D-Programming-Language/dmd/pull/1462). Lista dla tej rodziny słów kluczowych to [tutaj] (http://dlang.org/traits.html#specialkeywords). –

+1

hm to dodaje dużo kodu, jeśli używasz go wiele razy ... jego nie jest to idealne rozwiązanie – Quonux

5

Aby rozwinąć na jakiej CyberShadow said, ponieważ można uzyskać pełną nazwę funkcji za pomocą __FUNCTION__, można również uzyskać funkcję jako symbol za pomocą wstawek:

import std.stdio; 
import std.typetuple; 

void callee(string file=__FILE__, int line=__LINE__, string func=__FUNCTION__)() 
{ 
    alias callerFunc = TypeTuple!(mixin(func))[0]; 
    static assert(&caller == &callerFunc); 

    callerFunc(); // will eventually overflow the stack 
} 

void caller() 
{ 
    callee(); 
} 

void main() 
{ 
    caller(); 
} 

Stos wyleje się tutaj ponieważ te dwie funkcje kończą się nawzajem rekursywnie w nieskończoność.

2

Znalezienie dzwoniącego jest czymś, co robią debuggery i zazwyczaj wymaga zbudowania programu z włączonymi symbolicznymi przełącznikami informacji debugowania. Odczytywanie informacji o debugowaniu w celu ustalenia tego jest wysoce zależne od systemu i jest dość zaawansowane.

Mechanizm rozwijania wyjątków znajduje również wywołującego, ale tabele te nie są generowane dla funkcji, które ich nie potrzebują, a tabele nie zawierają nazwy funkcji.

+0

Co jeśli poproszę o funkcję '__CLASS__', ponieważ istnieją już' __FILE__', '__LINE ___' i '__FUNCTION__'? Będąc na tym polu, prawdopodobnie powinienem również poprosić o "__MODULE__". Jestem bardzo chętny do "zrobienia wymaganej papierkowej roboty" przy okazji. – Kris

+0

'__MODULE__' jest już zaimplementowany. Możesz wyodrębnić klasę z '__FUNCTION__', ponieważ jest w pełni kwalifikowana. –

+0

@CyberShadow Mogłem, ale dlaczego potrzebować bałaganu? Wydaje się, że zbyt dobrze pasuje do innych magicznych stałych, by nie być tam dla mnie. Tak dobrze, że jego brak można uznać za nieco zaskakujący. Przeczytałem "__MODULE__", ponieważ nie ma go w próbce kodu. Mój błąd. – Kris

Powiązane problemy