2015-12-22 19 views
12

Nel contesto di un'applicazione C++ 14, che usa uno schema che può essere così riassunti (test riproducibile minima):errore determinare un tipo di ritorno generico in C++ 11

template <class Container> 
struct LocateFunctions {  
    auto get_it() const // <-- here is the problem 
    { 
    auto ret = typename Container::Iterator(); 
    return ret; 
    } 
}; 

template <typename T> 
struct A : public LocateFunctions<A<T>> {  
    struct Iterator {}; 
}; 

int main() { 
    A<int> a; 
} 

Questo approccio compila e funziona perfettamente in C++ 14, con compilatori GCC e Clang.

Ora voglio migrare la mia applicazione a Windows e per questo sto usando MinGW. Sfortunatamente, la sua ultima versione porta GCC 4.9 che non compila C++ 14. Questo non sembra un problema serio perché posso riscrivere i costrutti C++ 14 in C++ 11. Così, riscrivo il metodo get_it() come segue:

typename Container::Iterator get_it() const 
{ 
    auto ret = typename Container::Iterator(); 
    return ret; 
} 

Purtroppo lo fa senza compilazione. Entrambi i compilatori producono il seguente errore:

error: no type named ‘Iterator’ in ‘struct A<int>’ 
    typename Container::Iterator get_it() const 
          ^

Ho anche provato:

auto get_it() const -> decltype(typename Container::Iterator()) 
{ 
    auto ret = typename Container::Iterator(); 
    return ret; 
} 

ma ho esattamente lo stesso errore.

Poiché due compilatori non riconoscono il tipo di ritorno, suppongo sia impossibile determinarlo. Ma non so davvero perché.

Qualcuno potrebbe spiegarmi perché non compilare ed eventualmente un modo per refactoring in C++ 11 che compila?

risposta

16

Stai utilizzando CRTP; LocateFunctions è un'istanza con una specializzazione incompleta di A (A<int>), quindi l'accesso ai membri di quella specializzazione fornisce il messaggio di errore piuttosto ingannevole ("no ... nome ... in ..." invece di "... è incompleto"). Tuttavia, nel tuo esempio la funzione temploid get_it è solo (se mai) istanziato dopo A<int> è infatti definito, rendendo il typename-specifier ben formato.

Per quanto riguarda una soluzione alternativa, provare a ottenere un effetto simile, ad es. via

template <typename T=Container> 
typename T::Iterator get_it() const 
{ 
    static_assert(std::is_same<T, Container>{}, "You ain't supposed to supply T!"); 
    auto ret = typename T::Iterator(); 
    return ret; 
} 

Demo con GCC 4.9.

+7

Temploid? È una parola? – Quentin

+6

@Quentin Sì. Denota membri non di modelli di modelli, interessati da un determinato DR aperto 15 anni fa. – Columbo

+3

upvote per temploid! – Barry

Problemi correlati