2015-09-01 18 views
8

Si consideri il seguente codice:Perché questa dichiarazione di una funzione nella classe template non è valida?

template<int X, int Y> 
struct S 
{ 
    typedef int func(int,float) const; 
}; 

template<int X> 
struct D : public S<X,6> 
{ 
    typename S<X,6>::func func; 
}; 
template<int X> 
int D<X>::func(int,float) const 
{ 
    return 1; 
} 
//---------------- 
struct W : public S<7,8> 
{ 
    S<7,8>::func func; 
}; 
int W::func(int,float) const 
{ 
    return 2; 
} 

#include <iostream> 
int main() 
{ 
    W w; 
    std::cout << w.func(1,4.3) << "\n"; 
    D<3> d; 
    std::cout << d.func(1,4.3) << "\n"; 
} 

Se commento il codice che dichiara di classe D e D::func() così come le linee corrispondenti nel main(), il codice viene compilato normalmente, e vedo 2 in uscita, come previsto.

Ma quando faccio il modello di classe derivata (aggiungendo typename prima dichiarazione di funzione, come S<X.6> è un ambito dipendente), ottengo i seguenti errori:

test.cpp:13:27: error: no ‘int D<X>::func(int, float) const’ member function declared in class ‘D<X>’ 
int D<X>::func(int,float) const 
         ^
test.cpp: In instantiation of ‘struct D<3>’: 
test.cpp:32:10: required from here 
test.cpp:10:27: error: field ‘D<3>::func’ invalidly declared function type 
    typename S<X,6>::func func; 
         ^
  • Perché non posso dichiarare func in una classe derivata da template, mentre nella classe non-template è OK?
  • Che cosa è esattamente "tipo di funzione dichiarato non valido"? cosa non è valido qui?
+0

Ho la sensazione che ciò sia tecnicamente valido per [dcl.fct]/10 nelle specifiche, ma dichiarare una funzione con un typedef dipendente è come un caso d'angolo di un caso d'angolo: non sono sicuro se alcuni compilatori lo gestirò come ti aspetti. – TartanLlama

+0

Direi che 'S ' potrebbe essere specializzato nell'ultimo caso, quindi la definizione di' D :: func' potrebbe diventare non valida. – Jarod42

+0

@ Jarod42 Sembra che abbiamo bisogno di 'function_typename' così come' typename': p – TartanLlama

risposta

3

N3337 [dcl.fct]/10: Un typedef del tipo di funzionamento può essere utilizzato per dichiarare una funzione, ma non devono essere utilizzati per definire una funzione.

Con questa regola, sia D sia W sono tecnicamente ben formati. Penso che la ragione per cui questo non è compilato con GCC o Clang è che dichiarare una funzione con un typedef è davvero raro. Dichiarare una funzione con un membro typedef dipendente da un parametro template è ancora più raro. Sembra che tu abbia appena colpito un angolo buio in cui il supporto del compilatore è limitato.

Stranamente, MSVC in realtà does the right thing qui.

L'opzione migliore è probabilmente trovare un modo diverso di esprimere le tue lezioni. Non posso dare alcun consiglio diretto senza sapere di più sul problema che stai cercando di risolvere, ma se fai una nuova domanda con i dettagli possiamo dare qualche suggerimento.

Si potrebbe anche pensare di presentare una segnalazione di bug per GCC e Clang.


Edit:

Tuttavia, come Jarod42 ha sottolineato, il tipo dipendente potrebbe in seguito essere definito come qualcosa di diverso da un tipo di funzione, rendendo la dichiarazione non valida. Il motivo per cui MSVC funziona dove GCC e Clang non è la stessa ragione per cui MSVC non richiede typename in alcuni punti: non implementa correttamente la ricerca in due fasi. Avere questo caso completamente specificato richiederebbe qualcosa come function_typename per contrassegnare un nome dipendente come un tipo di funzione. Penso che dichiarare una funzione basata su un tipo dipendente sia sottodescritto e incoerente in quanto si tratta di un caso molto raro.

+2

Anche 'function_typename' non è sufficiente se la firma può essere diversa dalla definizione (o richiederebbe una nuova definizione per la specializzazione). – Jarod42

+0

@ Jarod42 Hai ragione, avrebbe bisogno di dichiarare esplicitamente la firma che rappresenta typedef, che distrugge completamente l'intero punto di fare questo in primo luogo. – TartanLlama

+0

Perché questo sarebbe un problema, che una specializzazione invalida la dichiarazione? C'è qualche ipotesi che la dichiarazione sia valida, che non deve essere infranta dopo un certo punto? – Ruslan

0

Come il messaggio di errore indica: In Dfunc non è una funzione membro, quindi non è possibile fornire una definizione per questo. È un membro con tipo S<X,6>::func.

+2

Ma funziona per 'W'. – Ruslan

Problemi correlati