2017-05-25 3 views
0

J'ai pris le projet sur lequel je travaille et l'ai raccourci à trois brefs fichiers qui reproduisent ce qui se passe. Je travaille avec l'IDE Code :: Blocks en utilisant g ++ sous la norme 2011. Les fichiers sont main.cpp, thing.cpp et thing.h. L'en-tête (.h) a des déclarations et la source (.cpp) a des implémentations. Les fichiers thing définissent une classe Thing avec un paramètre de modèle T. Tous Thing est détenir un objet de type T (il ne fait essentiellement rien).Pourquoi l'inclusion d'une en-tête entraîne-t-elle une erreur «utilisation de l'auto avant déduction de l'auto»?

main.cpp:

#include <iostream> 
#include "thing.h" 

int main(){ 
    Thing<int> a(9); 
    Thing<double> b(3.2); 
    auto c = a + b; 
    c.display(); 

    return 0; 
} 

thing.h:

#ifndef THING_H 
#define THING_H 

template<typename T> 
class Thing{ 
private: 
    T content; 
public: 
    Thing(const T& content); 
    ~Thing(){}; 

    T get_content() const; 

    void display(); 
}; 

template<typename S, typename T> 
auto operator+(const Thing<S>& s, const Thing<T>& t); 

#endif // THING_H 

thing.cpp:

#include "thing.h" 
#include <iostream> 

template<typename T> 
Thing<T>::Thing(const T& content) 
:content(content){} 

template<typename T> 
void Thing<T>::display(){ 
    std::cout << content << '\n'; 
} 

template<typename T> 
T Thing<T>::get_content() const { 
    return content; 
} 

template<typename S, typename T> 
auto operator+(const Thing<S>& s, const Thing<T>& t){ 
    S s_content = s.get_content(); 
    T t_content = t.get_content(); 
    Thing<typename std::common_type<S, T>::type> sum = s_content + t_content; 
    return sum; 
} 

Voici le comportement étrange: le code compilera ou non en fonction de la ligne #include "thing.h". L'utilisation thing.h ici ne compilera pas, ce qui provoque une erreur:

error: use of 'auto operator+(const Thing<S>&, const Thing<T>&) [with S = int; T = double]' before deduction of 'auto' 
error: invalid use of 'auto' 

La modification de cette ligne #include "thing.cpp" permet au code de compiler sans problèmes et qu'il fonctionne comme prévu (il sort 12.2 à la console).

Ma question est: Qu'est-ce que le compilateur fait différemment dans les deux cas? Comment est-ce que je peux changer le code pour éliminer cette erreur quand includ ing l'en-tête?

Merci d'avance.

+4

Vous devriez probablement vous demander [pourquoi vous n'êtes pas mise en œuvre de vos modèles dans un en-tête] (https: // stackoverflow.com/questions/495021/why-can-templates-only-be-implemented-in-the-header-file) en premier lieu? Il est impossible pour un appelant de déduire le 'auto' donné uniquement' 'auto-opérateur + (const Thing & s, const Thing & t);' pour travailler avec le code – WhozCraig

+0

@WhozCraig Pourquoi l'appelant n'a-t-il accès qu'à l'en-tête et non l'implémentation dans le fichier source? En fait, comment un appelant accède à la source dans d'autres situations? Mon impression était que lorsque la fonction est appelée, le compilateur remplacera dans l'implémentation, dans lequel le type de retour automatique peut être déduit – Johan

+0

Le compilateur ne peut pas faire cela parce qu'il a besoin de la définition de modèle à portée de main quand vous êtes sur le point de l'utiliser.Main est une unité de traduction, Thing en est une autre, et la définition de la classe modèle de 'Thing' n'existe pas dans l'unité principale. –

Répondre

0

Les types de retour déduits ont été introduits en C++ 14.

Coliru reproduces your problem in C++11 mode, mais shows the code working in C++14.

Et, bien sûr, bien que ce ne soit pas la cause immédiate de votre problème, it is likely that you will have to move your template definitions into the/a header.

Oh, et voici le minimal testcase vous devriez avoir testé avec:

template <typename T> 
auto foo(T a) 
{ 
    return a; 
} 

int main() 
{ 
    foo(42); 
} 
+0

Le code a fonctionné pour l'OP, de leur propre aveu, quand 'thing.cpp' était inclus ** à la place ** de' thing.h'. Ce n'est donc pas un problème C++ 11 vs C++ 14. C'est un modèle qui n'est pas défini dans un problème d'en-tête. Ce qui rend seulement le lien dans votre réponse pertinent. – StoryTeller