Je travaille sur une implémentation des nombres complexes. La classe, Complex , a deux membres privés, real_part et imaginary_part . Je voudrais remplacer l'opération de multiplication comme suit:
In file included from main.cpp:2:
complex.hpp: In instantiation of âComplex operator*(T, D) [with T = Complex; D = Complex]â:
main.cpp:13:17: required from here
complex.hpp:43:16: error: cannot convert âComplexâ to âdoubleâ in assignment
real_a = lhs;
~~~~~~~^~~~~
complex.hpp:53:16: error: cannot convert âComplexâ to âdoubleâ in assignment
real_b = rhs;
~~~~~~~^~~~~
complex.hpp: In instantiation of âComplex operator*(T, D) [with T = Complex; D = int]â:
main.cpp:14:20: required from here
complex.hpp:43:16: error: cannot convert âComplexâ to âdoubleâ in assignment
real_a = lhs;
~~~~~~~^~~~~
complex.hpp:48:22: error: request for member âreal_partâ in ârhsâ, which is of non-class type âintâ
real_b = rhs.real_part;
~~~~^~~~~~~~~
complex.hpp:49:27: error: request for member âimaginary_partâ in ârhsâ, which is of non-class type âintâ
imaginary_b = rhs.imaginary_part;
~~~~^~~~~~~~~~~~~~
Mes constructeurs ressemblent à:
Complex a(4.0, 8.0); Complex b(8, 16); auto prod = a*b; auto prod2 = a * 2;
et:
Complex(T real, T imaginary)
{
real_part = real;
imaginary_part = imaginary;
}
Lorsque j'essaye de multiplier deux complexes ensemble:
Complex::Complex()
{
real_part = 0.0;
imaginary_part = 0.0;
}
Je reçois l'erreur suivante:
template<typename T, typename D>
friend Complex operator * (T lhs, D rhs)
{
double real_a;
double real_b;
double imaginary_a;
double imaginary_b;
if(std::is_same<T, Complex>::value)//if lhs is a Complex
{
real_a = lhs.real_part;
imaginary_a = lhs.imaginary_part;
}
else //base type, some sort of number
{
real_a = lhs;
imaginary_a = 0;
}
if(std::is_same<D, Complex>::value)//if rhs is a Complex
{
real_b = rhs.real_part;
imaginary_b = rhs.imaginary_part;
}
else //base type, some sort of number
{
real_b = rhs;
imaginary_b = 0;
}
Complex result;
result.real_part = (real_b*real_a- imaginary_b*imaginary_a);
result.imaginary_part = (real_b*imaginary_a + imaginary_b*real_a);
return result;
}
3 Réponses :
Ceci est dû au fait que les deux branches du if sont compilées pour la même instatiation. Certaines de ces instanciations sont invalides.
Si vous pouvez travailler avec c ++ 17, vous pouvez remplacer if par if constexr , de cette façon seule la branche correcte est instanciée:
XXX
Pour le C ++ 11 strict, vous pouvez utiliser la surcharge de fonctions pour distinguer les deux types:
template<typename T>
static T getReal(T x)
{
return x;
}
static double getReal(Complex x)
{
return x.real_part;
}
template<typename T>
static T getImaginary(T x)
{
return 0;
}
static double getImaginary(Complex x)
{
return x.imaginary_part;
}
template<typename T, typename D>
friend Complex operator * (T lhs, D rhs)
{
double real_a = getReal(lhs);
double real_b = getReal(rhs);
double imaginary_a = getImaginary(lhs);
double imaginary_b = getImaginary(rhs);
Complex result;
result.real_part = (real_b*real_a- imaginary_b*imaginary_a);
result.imaginary_part = (real_b*imaginary_a + imaginary_b*real_a);
return result;
}
Une instanciation d'un modèle doit vérifier le type dans son intégralité.
Bien que vous puissiez utiliser if constexpr pour sélectionner une branche au moment de la compilation, je pense que c'est en fait plus simple l'ancien- façon façonnée, avec surcharge et sans condition:
// Mutating multiplication as a member
template<typename T>
Complex<T>& Complex<T>::operator*=(const Complex<T>& rhs)
{
auto real = real_part;
auto imaginary = imaginary_part;
real_part = real * rhs.real_part - imaginary * rhs.imaginary_part;
imaginary_part = imaginary * rhs.real_part + real * rhs.imaginary_part;
return *this;
}
// These are free non-friend functions.
template<typename T>
Complex<T> operator*(Complex<T> lhs, const Complex<T>& rhs)
{
return lhs *= rhs;
}
template<typename T>
Complex<T> operator*(const Complex<T>& lhs, T rhs)
{
return lhs * Complex(rhs, 0);
}
template<typename T>
Complex<T> operator*(T lhs, const Complex<T>& rhs)
{
return rhs * lhs;
}
Je suis d'accord avec la réponse de Michael Veksler , ie , la règle de base est que le modèle fonctionne sera compilé en plusieurs instances selon la façon dont vous avez appelé la fonction. La compilation sera faite pour tout le code tandis que l'assertion de std :: is_same est à l'exécution. Par conséquent, la compilation ne passera pas car certaines branches de votre code ne sont pas valides pour des types d'arguments spécifiques (par exemple int pour l'instruction real_b = rhs.real_part ).
À simplifier le code, nous pouvons définir un autre constructeur pour le type Complex en transposant d'abord des types numériques simples ( eg , int ou double ) en type Complex .
static Complex operator * (const Complex & lhs, const Complex & rhs)
{
Complex result(lhs.real_part*rhs.real_part - lhs.imaginary_part * rhs.imaginary_part,
lhs.real_part*rhs.imaginary_part + lhs.imaginary_part * rhs.real_part);
return result;
}
Ensuite, nous pouvons modifier la fonction de surcharge de l'opérateur * comme p >
template<typename T>
Complex(T real, T imaginary = 0)
{
real_part = real;
imaginary_part = imaginary;
}
NOTEZ que: les arguments d'entrée seront automatiquement convertis dans le type Complex par le constructeur nouvellement défini ou le constructeur de copie. De plus, le résultat renvoyé est construit avec le nouveau constructeur.
Ajoutez également vos constructeurs
Complex. Et la version de C ++ que vous utilisez?Salut @ P.W, j'ai ajouté les constructeurs. J'utilise C ++ 11. J'ai réalisé que mon exemple manquait un peu; Je voudrais pouvoir multiplier deux
Complexs ensemble ainsi que par ex. unintet unComplex.J'ai demandé la version car en C ++ 17, vous pouvez utiliser
constexprpour éliminer les branches incorrectes. En C ++ 11, vous devez utiliser la spécialisation. Je voulais poster une réponse mais quelqu'un m'a battu. :)