2013-12-15 20 views
8

C++ ma ADL (Argument Dependent Lookup), według którego, jak sama nazwa wskazuje, kontekst (przestrzeń nazw) funkcji może być implikowany z kontekstu (przestrzeni nazw) (dowolnego) argumentu (ów).Obejście problemu odwrotnego wywołania zależnego od argumentu?

fun(a); // if the type of a is in namespace ns deduce ns::f if available 

Moje pytanie brzmi, czy rewers jest również możliwy za pomocą jakiejś techniki? Odwrotnie mam na myśli, jeśli kontekst (przestrzeń nazw) można wywnioskować z kontekstu wywołanej funkcji. Jakieś "Wyszukiwanie zależne od funkcji" (FDL). Fałszywy kod:

ns::fun(a); // deduce ns::a if available 

Nie mogę znaleźć sposobu na zrobienie tego. To ograniczenie jest szczególnie denerwujące w przypadku kodowania funkcji funkcji. Chciałbym wiedzieć, czy istnieje technika symulacji tej funkcji (C++ 11 też byłoby w porządku). Kod Fałszywy:

ns::fun(Saturday, Tuesday); // Saturday/Tuesday are enum values in namespace ns; 

Zwłaszcza jeśli istnieje obejście enum s.

Ten kod ilustruje problem:

namespace longname{ 
    class A{}; 
    void fun(A const& a){} 
    A global_a; 

    enum Days { Saturday,Sunday,Tuesday,Wednesday,Thursday,Friday}; 
    void gun(Days d1, Days d2){}  
} 

int main(){ 
    longname::A a; 
    fun(a); // cool, longname::fun(a) not necessary, fun is deduced from context 

    longname::fun(global_a); // error, not cool, global_a context not deduced, 
    // must use then longname::fun(longname::global_a) 
    longname::gun(Saturday, Tuesday); // error, particularly not cool, the Saturday is not deduced from context 
    // must use then longname::gun(longname::Saturday, longname::Tuesday) 
    // or at best gun(longname::Saturday, longname::Tuesday) 
} 

EDIT: @jrok sugerowane obejście w oparciu o zdefiniowanie nazw zagnieżdżonych. W przypadku enum otrzymuję ten kod. Które nadal ma trochę hałasu (w rzeczywistości nie ma żadnego "zależnego" wyszukiwania), ale jest to poprawa.

namespace longname{ 
    namespace days{ 
     enum _ { Saturday,Sunday,Tuesday,Wednesday,Thursday,Friday}; 
    } 
    void gun(days::_ d1, days::_ d2){} 
} 

int main(){ 
    using namespace longname::days; // some noise still here 
    longname::gun(Saturday, Tuesday); 
} 

nie używam enum class bo wtedy Saturday, Sunday itp nie mogą być przyniesione bezpośrednio w zakres (w rzeczywistości using longname::days::_ dałby mi błąd kompilacji)

+0

ok, po złożeniu moje pytanie: Mam powiązane pytanie na prawym panelu http://stackoverflow.com/questions/14163667/why-does-c11-not-support-name-lookup-like- to? rq = 1. Prawdopodobnie różnica polega na tym, że nie kwestionuję języka, ale szukam obejścia techniki. – alfC

+2

Obejście: Umieść wyliczenie w zagnieżdżonej przestrzeni nazw i powiedz 'using namesname longname :: nested;' in 'main'. – jrok

+0

@jrok, fajnie, to zbliża się do rozwiązania (dodałem Twoją sugestię do pytania). – alfC

Odpowiedz

2

tak i nie. Głównie nie.

Złe wieści są takie, że wyliczenie znajduje się poza bieżącym zakresem, takim jak Tuesday itd., Więc nie można go przekazać do funkcji, nawet jeśli ta funkcja została zadeklarowana w przestrzeni nazw, w której wyliczenie było widoczne. Dzieje się tak dlatego, że wyszukiwanie argumentów występuje najpierw podczas pisania wywołania funkcji, a argumentów nie można przekazać do gun, a następnie przeprowadzić wyszukiwanie nazwy. Nic nie może tego zmienić - jednak istnieją również dobre wiadomości.

Po pierwsze wydaje się, że potrzebujesz zachowania, które mapuje ns::foo(arg1, arg2) ->{using namespace ns; ns::foo(arg1, arg2);}. Wywołania funkcji i szablony nie mogą tego zmienić, ale makra rodzaj puszki i ja włączone i przykład.

Podałem również podstawowy przykład wyszukiwania zależnego od argumentów. Możesz zobaczyć, że funkcje out-of-scope GetMonday i GetTuesday (które zwracają twój wyliczenie poza zasięgiem) można znaleźć za pomocą tego mechanizmu, ponieważ zawierałeś jeden typ z tego obszaru nazw. RegisterNamespace::val dodaje ukryty obszar nazw do zakresu, gdy kompilator próbuje znaleźć GetMonday, a GetMonday zwraca wartość Days, która umożliwia kompilatorowi znalezienie foo.

Naprawdę chcesz, aby kompilator zmienił zakres, dodając dodatkowe przestrzenie nazw, gdy napotka funkcję z innej przestrzeni nazw. Jednak kompilator już wcześniej określił typy argumentów i faktycznie potrzebuje ich do opracowania innych możliwych alternatyw dla funkcji.

#include <iostream> 

namespace hidden { 

enum RegisterNamespace { val }; 

enum Days { 
    Monday, 
    Tuesday 
}; 

void foo(Days a , Days b){std::cout << "Called foo\n";} 

Days GetMonday(RegisterNamespace a = val){return Days::Monday;} 
Days GetTuesday(RegisterNamespace b = val){return Days::Tuesday;} 

} 

using namespace std; 

#define UseNamespace(ns, x) do {using namespace ns; x;} while (0) 

int main() 
{ 
    //with a macro 
    UseNamespace(hidden,hidden::foo(Monday, Tuesday)); 

    { 
    //foo is found by argument dependent lookup 
    using hidden::Days; 
    foo(Days::Monday,Days::Tuesday); 
    } 

    { 
    using r = hidden::RegisterNamespace; 
    //foo and GetMonday/GetTuesday are all found by argument dependent lookup 
    foo(GetMonday(r::val),GetTuesday(r::val)); 
    } 

    return 0; 
}