2010-06-01 11 views
70

Quale parte della specifica C++ limita la ricerca dipendente dall'argomento dall'individuazione di modelli di funzione nell'insieme di spazi dei nomi associati? In altre parole, perché l'ultima chiamata in main non riesce a compilare?Perché ADL non trova i modelli di funzione?

namespace ns { 
    struct foo {}; 
    template<int i> void frob(foo const&) {} 
    void non_template(foo const&) {} 
} 

int main() { 
    ns::foo f; 
    non_template(f); // This is fine. 
    frob<0>(f); // This is not. 
} 
+0

Vuol dire, che ci si aspetta di lavorare frob() senza scrivere ns :: frob()? – Simon

+0

Sì, nel modo di una funzione non modello. – Hugh

+0

FYI il codice di cui sopra non riesce in Comeau: http://www.comeaucomputing.com/tryitout/ - aggiungendo 'using namespace ns;' o la 'ns ::' qualificazione passa la compilazione. Questa è una buona domanda. – fbrereto

risposta

74

Questa parte spiega:

C++ standard 03 14.8.1.6:

[Nota: Per i nomi delle funzioni semplici, argomento di ricerca dipendente (3.4.2) si applica anche quando il nome della funzione non è visibile nell'ambito della chiamata. Questo perché la chiamata ha ancora la forma sintattica di una chiamata di funzione (3.4.1). Ma quando viene utilizzato un modello di funzione con argomenti di template espliciti, la chiamata non ha la forma sintattica corretta a meno che non ci sia un modello di funzione con quel nome visibile nel punto della chiamata. Se nessun nome è visibile, la chiamata non è sintatticamente ben formata e la ricerca dipendente dall'argomento non si applica. Se alcuni di questi nomi sono visibili, si applica la ricerca dipendente da argomento e altri modelli di funzioni possono essere trovati in altri spazi dei nomi.

namespace A { 
    struct B { }; 
    template<int X> void f(B); 
} 
namespace C { 
    template<class T> void f(T t); 
} 
void g(A::B b) { 
    f<3>(b); //ill-formed: not a function call 
    A::f<3>(b); //well-formed 
    C::f<3>(b); //ill-formed; argument dependent lookup 
       // applies only to unqualified names 
    using C::f; 
    f<3>(b); //well-formed because C::f is visible; then 
       // A::f is found by argument dependent lookup 
} 
+4

+1 Bella risposta. – fbrereto

+0

Eccellente - grazie. – Hugh

+0

Ah, non sono riuscito a trovare tale riferimento :) +1 –

0

Edit: No, questo non è giusto. Vedi @Kornel's answer.


io non sono del tutto sicuro, ma dopo aver consultato Stroustrup "Il linguaggio di programmazione C++" Penso che la sezione Appendice C 13.8.4 potrebbe essere la causa.

Poiché frob è un modello, è possibile concepirlo per il numero i=0 in un punto dopo averlo chiamato. Ciò significa che l'implementazione sarebbe lasciata con due possibili modi di scegliere quale frob chiamare come appare, ma può sceglierlo nel punto di istanziazione o alla fine dell'elaborazione dell'unità di traduzione.

Quindi, penso che il problema è che si potrebbe fare

namespace ns { 
    struct foo {}; 
    template<int i> void frob(foo const&) {} 
} 

int main() { 
    ns::foo f; 
    frob<0>(f); 
    return 0; 
} 

namespace ns { 
    template<> void frob<0>(foo const&) { /* Do something different*/ } 
} 
+0

No, prendi gli spazi dei nomi e hai ancora il tuo problema, vero? La specializzazione dopo l'uso è un problema normale in C++, la forma specializzata non viene utilizzata se dichiarata dopo. –

+0

@Kornel: Ah sì, questo dà un errore diverso, uno in più in linea con quello che ho descritto. Abbastanza onesto, grazie per averlo indicato. – Troubadour

3

vorrei perfezionare risposta un po 'accettata. Non è chiaro nella questione OP, ma la parte importante dallo standard (citato da Kornel) è questo (sottolineatura mia):

Ma quando si utilizza un modello di funzione con argomenti template espliciti, la chiamata non ha la forma sintattica corretta

quindi ciò che è proibito si basa su ADL e utilizza argomenti di template espliciti. Sfortunatamente l'utilizzo di argomenti modello non di tipo richiede l'utilizzo di argomenti espliciti (a meno che non abbiano valori predefiniti).

Qui di seguito è il codice di esempio che mostra questo .:

[live]

#include <string> 
#include <utility> 

namespace C { 
    struct B { }; 
    template<class T> void f(T t){} 
} 

void g(C::B b) { 
    f(b);   // OK 
    //f<C::B>(b); // ill-formed: not a function call, but only 
        // because explicit template argument were used 

    std::string s; 
    move(s);      // OK 
    //move<std::string&>(s);  // Error, again because 
           // explicit template argument were used 
    std::move<std::string&>(s); // Ok 
} 

int main() 
{ 
C::B b; 
g(b); 
} 
Problemi correlati