2013-12-15 9 views
8

C++ ha ADL (Argument Dependent Lookup) mediante il quale, come descrive il nome, il contesto (spazio dei nomi) di una funzione può essere implicito dal contesto (spazio dei nomi) di (qualsiasi) argomento (i).Soluzione alternativa per l'inverso della ricerca dipendente dall'argomento?

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

La mia domanda è se il contrario è anche possibile da qualche tecnica? In senso inverso intendo se il contesto (spazio dei nomi) può essere dedotto dal contesto della funzione chiamata. Una sorta di "funzione di ricerca dipendente" (FDL). Codice falso:

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

Non riesco a capire un modo per farlo. Questa limitazione è particolarmente fastidiosa per i valori enum utilizzati per codificare le opzioni delle funzioni. Mi piacerebbe sapere se esiste una tecnica per simulare questa caratteristica (anche il C++ 11 andrebbe bene). Codice Falso:

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

soprattutto se v'è una soluzione per enum s.

Questo codice illustra il problema:

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 ha suggerito una soluzione basata sulla definizione dello spazio dei nomi nidificato. Per il caso enum, ottengo questo codice. Che ha ancora un po 'di rumore (non c'è davvero nessuna ricerca "dipendente") ma è un miglioramento.

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); 
} 

non sto usando enum class perché poi Saturday, Sunday, ecc non può essere Brough direttamente nel campo di applicazione (in realtà using longname::days::_ mi avrebbe dato un errore di compilazione)

+0

ok, dopo aver presentato la mia domanda: Ho una domanda relativa sul pannello di destra http://stackoverflow.com/questions/14163667/why-does-c11-not-support-name-lookup-like- questo? rq = 1. Probabilmente, la differenza qui è che non sto mettendo in discussione la lingua, ma sto cercando una tecnica alternativa. – alfC

+2

Soluzione alternativa: inserire l'enum in uno spazio dei nomi annidato e pronunciare 'using namespace longname :: nested;' in 'main'. – jrok

+0

@jrok, cool, che si avvicina a una soluzione (ho aggiunto il tuo suggerimento alla domanda). – alfC

risposta

2

Sì e no. Per lo più no.

La cattiva notizia è se un enum è al di fuori dell'ambito corrente, come ad esempio Tuesday, quindi non può essere passato a una funzione, anche se tale funzione è stata dichiarata in uno spazio dei nomi in cui l'enum era visibile. Questo perché la ricerca di argomenti si verifica prima quando si scrive una chiamata di funzione e gli argomenti non possono essere passati a gun e quindi si verifica la ricerca del nome. Nulla può cambiarlo - tuttavia ci sono anche buone notizie.

In primo luogo, sembra che sia necessario un comportamento per mappare ns::foo(arg1, arg2) ->{using namespace ns; ns::foo(arg1, arg2);}. Chiamate e modelli di funzione non possono cambiare questo, ma il tipo di macro di can e ho incluso ed esempio.

Inoltre ho fornito un esempio di base di ricerca dipendente dall'argomento. È possibile notare che le funzioni fuori ambito GetMonday e GetTuesday (che restituiscono l'enumerazione fuori ambito) possono essere trovate utilizzando questo meccanismo semplicemente perché è stato incluso un tipo da tale spazio dei nomi. RegisterNamespace::val aggiunge lo spazio dei nomi nascosto all'ambito quando il compilatore sta cercando di trovare GetMonday e GetMonday restituisce un Days che consente al compilatore di trovare foo.

In realtà si desidera che il compilatore modifichi l'ambito aggiungendo spazi dei nomi aggiuntivi quando incontra una funzione proveniente da un altro spazio dei nomi. Tuttavia il compilatore ha già determinato i tipi di argomenti per allora, e in realtà ha bisogno di loro per elaborare altre possibili alternative alla funzione.

#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; 
} 
Problemi correlati