2015-12-22 2 views
12

Dans le cadre d'une application 14 C++, j'utiliser un système qui pourrait être repris comme suit (test reproductible minimum):détermination d'un type générique de retour en 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; 
} 

Cette approche compile et fonctionne parfaitement en C++ 14, avec les compilateurs GCC et Clang.

Maintenant, je veux migrer mon application vers Windows et pour cela j'utilise MinGW. Malheureusement, sa dernière version apporte GCC 4.9 qui ne compile pas C++ 14. Cela ne semble pas être un problème sérieux car je peux réécrire les constructions C++ 14 en C++ 11. Donc, je réécris la méthode get_it() comme suit:

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

Malheureusement il ne fait pas la compilation. Les deux compilateurs produisent l'erreur suivante:

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

J'ai aussi essayé:

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

mais je reçois exactement la même erreur.

Étant donné que deux compilateurs ne parviennent pas à reconnaître le type de retour, je suppose qu'il est impossible de le déterminer. Mais je ne sais pas vraiment pourquoi.

Quelqu'un pourrait-il m'expliquer pourquoi ne pas compiler et éventuellement un moyen de refactoriser en C++ 11 qui compile?

Répondre

16

Vous utilisez CRTP; LocateFunctions est instanciée avec une spécialisation incomplète de A (A<int>), donc l'accès aux membres de cette spécialisation donne le message d'erreur plutôt trompeur ("no ... named ... in ..." au lieu de "... is incomplete"). Cependant, dans votre exemple la fonction temploid get_it est seulement (si jamais) instancié après A<int> est en effet défini, ce qui rend le typename-spécificateur bien formé.

Pour une solution de contournement, essayez d'obtenir un effet similaire, par ex. 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 avec GCC 4.9.

+7

Temploïde? Est-ce un mot? – Quentin

+6

@Quentin Oui. Il dénote des membres non modèles de modèles, affectés par un certain DR ouvert il y a 15 ans. – Columbo

+3

upvote pour temploid! – Barry