2011-04-18 13 views
8

Perché questo non riesce a compilare con GCC 4.4?Sovraccarico di modelli di funzioni nei namespace

template<typename T> 
class A { 
public: 
    void foo() { 

    } 

private: 
    T x; 
}; 

namespace Ns { 
template<typename T> 
void do_it (A<T> a) { 
    a.foo(); 
} 
}; 

template<typename T> 
void myfun (T x) { 
    Ns::do_it (x); 
} 

template<typename T> 
class B { 
public: 
    void bar() { 

    } 

private: 
    T x; 
}; 

namespace Ns { 
template<typename T> 
void do_it (B<T> b) { 
    b.bar(); 
} 
}; 

int main() { 
    A<int> a; 
    B<int> b; 

    myfun (a); 
    myfun (b); // error: no matching function call to do_it(B<int>&) 

    return 0; 
} 

Deve avere qualcosa a che fare con lo spazio dei nomi di do_it. Quando rimuovo lo spazio dei nomi attorno ad esso, viene compilato.

Contesto: Sto creando un set di funzioni che possono essere utilizzate con molte classi di contenitori differenti. Per gestire le diverse interfacce in modo uniforme, utilizzo le funzioni freestanding che sono sovraccariche per ciascuna delle classi contenitore. Queste funzioni devono essere inserite in uno spazio dei nomi per evitare di ingombrare lo spazio dei nomi globale con loro.

Le definizioni per B devono essere pensate come provenienti da un file di intestazione diverso da quelli di A, quindi il riordino non è un'opzione.

+0

È un errore di battitura! Lo è stato inghiottito dall'HTML. –

+0

VS 2010 compila il codice sopra, e credo che sia corretto nel farlo, ma questo è un esempio difficile. Bella domanda! –

+0

Lo stesso con VS2008, l'ho appena controllato. Potrebbe essere un bug in GCC o la loro interpretazione è diversa da quella di Microsoft? Il fatto che funzioni senza uno spazio dei nomi potrebbe essere un bug, vero? –

risposta

6

Il motivo è che solo l'ADL viene eseguita al punto della chiamata. Altre ricerche di funzioni vengono eseguite solo nella definizione del modello di funzione myfun.

E in tale contesto di definizione, viene dichiarato solo il sovraccarico do_it che accetta lo A<int>.

Modifica: se si desidera avere un riferimento standard per questo, fare riferimento a [temp.dep.candidate] e [temp.res] p1.

+0

Esiste un modo standard per risolvere questo problema utilizzando gli spazi dei nomi? –

+2

@Mark se si desidera avere funzioni nello spazio dei nomi 'Ns' considerato, è possibile derivare' B 'da una classe fittizia definita in tale spazio dei nomi, in modo che ADL guardi nello spazio dei nomi' Ns'. Oppure puoi passare gli argomenti del template a 'B ' che associano la specializzazione generata con 'Ns'. Ad esempio 'B >' (ADLAssociator potrebbe essere solo un modello di classe piccola che memorizza solo 'T t;'). Oppure si passano le classi associate come ulteriori argomenti fittizi: 'B '. Ci sono molte opzioni per questo. Il più pulito sembra essere semplicemente derivare 'B' da una classe o definirla in' NS'. –

+5

Che ne dici di cambiare la funzione libera in un membro di una classe statica: 'namespace Ns {template struct dispatch; } '(dichiararlo in primo piano), quindi per ogni nuovo tipo, aggiungere una specializzazione:' namespace Ns {template struct dispatch < B> {static void do_it (B x) {x.bar()}}; } ', e ha' template void myfunc (T t) {Ns :: dispatch :: do_it (t); } ' –