2015-10-20 15 views
6

Il seguente codice non viene compilato, a meno che la linea commentata sia commentata:C++ operatore virgola non compila

template <class T> struct R { static T& r(); }; 
struct M { 
    static char m(M&); 
    template <class T> static int m(const T&); 
}; 
template <class T> struct A; 
template <class T> 
struct B { 
    struct U { }; 
    struct V { M& operator,(U); }; 
    enum { v = sizeof(M::m((R<V>::r(), R<A<T>*>::r()))) }; 
}; 
template <class T> struct A { B<T> y; }; 
int main() 
{ 
// A<int>(); // Works if uncommented. 
    B<int>(); 
} 

verso l'operatore virgola, il compilatore pensa che ha bisogno di A<int> essere completo, anche se il codice tratta solo tra A<T>*. Non capisco perché. Fallisce con clang e g ++. Clang dice

h.cpp:13:36: error: field has incomplete type 'B<int>' 
template <class T> struct A { B<T> y; }; 
           ^
h.cpp:11:38: note: in instantiation of template class 'A<int>' requested here 
    enum { v = sizeof(M::m((R<V>::r(), R<A<T>*>::r()))) }; 
            ^
h.cpp:17:5: note: in instantiation of template class 'B<int>' requested here 
    B<int>(); 
    ^
h.cpp:8:8: note: definition of 'B<int>' is not complete until the closing '}' 
struct B { 
    ^
1 error generated. 

Ora sto seduto nel debugger il debug del compilatore :-) Penso che quello che sta accadendo è che il compilatore sta usando lookup argomento-dipendente per trovare corrispondenza operator, s e le classi associate e Gli spazi dei nomi per un puntatore a una classe includono la classe stessa, quindi il compilatore desidera che la classe sia completa. Può essere.

+0

quindi qual è la tua domanda? –

+0

Perché non viene compilato? Perché il compilatore desidera che 'A ' sia completo quando si guarda l'operatore '(B :: V, A *)'? Perché funziona quando la riga commentata non è commentata? –

+3

cosa ha detto l'errore emesso dal compilatore? –

risposta

0

si ottiene lo stesso messaggio di errore se si modifica principale di essere questo:

int main() 
{ 
    // A<int>(); // Works if uncommented. 

    auto& x = R<A<int>*>::r(); 
    B<int>(); 
} 

ho intenzione di andare su un arto qui e dire che è come voi ha accennato. La menzione di un puntatore a A<int> non causa un'espansione modello di A<int>.

Questo ha senso (per me), poiché equivale a menzionare un puntatore a un tipo dichiarato in avanti - non è necessario il tipo completamente definito in quel punto.

Forse qualcuno più saggio di me può trovare il passaggio nello standard che lo impone.

0

Al momento non capisco perché l'enumerazione non funzioni qui. Ma questo sembra funzionare:

static const int v = sizeof(M::m((R<V>::r(), R<A<T>*>::r()))); 

Compila con gcc-4.8.4, ma non riesce a compilare con clang-3.6. L'errore è lo stesso di prima.

I seguenti compila sia con:

template <class T> 
struct B { 
    struct U { }; 
    struct V { M& operator,(U); }; 
    static const int v; 
}; 

template <class T> 
const int B<T>::v = sizeof(M::m((R<V>::r(), R<A<T>*>::r())));