J'ai créé une structure basée sur un modèle et j'essaie de surcharger les opérateurs binaires. Pour une raison quelconque, la fonction ne renvoie pas le type de données correct, même si le type est correctement converti entre.
template<typename T>
struct Number{
const T value;
Number(T a) : value(a) {}
template<typename U>
auto operator*(Number<U> other){
auto new_value = value*other.value;
std::cout << typeid(new_value).name() << std::endl;
return Number(new_value);
}
};
Maintenant, si je réalise cette opération avec le code suivant appelé dans main. Il retourne le numéro du type du premier, pas le numéro du type le plus élevé.
auto b = Number<int>(6) * Number<double>(2.3); // this should be an int*double=double
std::cout << b.value << typeid(b.value).name() << std::endl;
auto c = Number<double>(2.3) * Number<int>(6);
std::cout << c.value << typeid(c.value).name() << std::endl;
La sortie est la suivante: D 13i D 13.8d
D'après ce que j'ai compris, le constructeur incorrect est appelé lorsque la fonction renvoie le nouveau Number(new_value)
. Je ne comprends pas comment et pourquoi cela se produit car new_value est du "type correct".
Dans l'étendue d'un modèle, le nom du modèle va représenter le nom de la classe injectée et non le modèle. Donc, il n'y aura pas de CTAD, et c'est à dessein
Utiliser return Number<decltype(new_value)>(new_value);
est la solution de contournement simple.
Vous retournez le premier type et non le second:
template<typename U>
auto operator*(Number<U> other){
auto new_value = value*other.value;
std::cout << typeid(new_value).name() << std::endl;
return Number(new_value);
}
Même si new_value
est un double, vous le stockez dans un Number<T>
.
Essayer:
template<typename U>
auto operator*(Number<U> other){
auto new_value = value*other.value;
std::cout << typeid(new_value).name() << std::endl;
return Number<decltype(new_value)>(new_value);
}
Comme StoryTeller souligne, dans une définition de modèle de classe, le nom de la classe fait référence à l'instance de classe spécifique (appelée injected-class-name) et non au nom du modèle.
Mais si vous souhaitez que la déduction d'argument de modèle de classe continue à s'appliquer, vous pouvez simplement qualifier le nom:
return ::Number(new_value);
::Number
fait référence au modèle de classe Number
et non au type spécifique Number<T>
. Mais cela pourrait être un peu trop magique pour les autres lecteurs de votre code, et utiliser simplement Number<decltype(new_value)>(new_value)
présente de nombreux avantages.