sobrecarga ambígua sobre os operadores de modelo
-
06-07-2019 - |
Pergunta
Eu estou trabalhando em duas classes de mensagens publicitárias que definem tipos de dados reais e complexos. Cada define classe sobrecarregado construtores, bem como os quatro operadores aritméticos +, -, *, / e cinco operadores de atribuição =, + = etc. Para evitar código repetindo, eu estava pensando em usar funções quando o esquerdo e direito modelo -hand-secundários argumentos de um operador são de um tipo de dados diferente:
// real.h
class Real {
public:
explicit Real(const double& argument) {...}
explicit Real(int argument) {...}
...
friend const operator*(const Real&; const Real&);
template <class T> friend const Real operator*(const Real&, const T&);
template <class T> friend const Real operator*(const T&, cont Real&);
// Here, T is meant to be a template parameter for double and int
// Repeat for all other arithmetic and assignment operators
};
// complex.h
class Complex {
public:
explicit Complex(const Real& realPart) {...}
explicit Complex(const Real& realPart, const Real& imaginaryPart) {...}
// Overload for double and int data types
...
friend const operator*(const Complex&, const Complex&);
template <class T> friend const Complex operator*(const Complex&, const T&);
template <class T> friend const Complex operator*(const T&, cont Complex&);
// Here, T is is a template parameter for Real, double and int
...
};
O problema aqui é que o código como:
//main.cpp
void main() {
Complex ac(2.0, 3.0);
Real br(2.0);
Complex cc = ac * br;
}
retorna o compilador ( gcc ) erro sobrecarga ambígua para 'operador *' em 'ac * br' , como o compilador não pode dizer a diferença entre:
-
template <class T> friend const Complex operator*(const Complex&, const T&)
[com T = real] -
template <class T> friend const Real operator*(const T&, cont Real&)
[com T = Complex]
Existe uma maneira para especificar que T não pode ser um complexo no operador de template * definição na classe Real? Ou eu tenho que fazer sem modelos e definir cada operador para cada combinação possível de tipos de dados argumento? Ou há uma maneira de reformular o código?
Solução
Ah, o problema dos operadores ...
Aumento criou uma biblioteca agradável para que, fornecendo um mínimo de lógica todas as outras variações são automagicamente adicionado para você!
Dê uma olhada Boost.Operators !
Agora, para o seu problema, na verdade, como você percebeu, você terá que definir ambos os sabores dos operadores (int e duplas) ao invés de usar um modelo genérico. Se houver um monte de lógica nestas operadores (o que duvido), você sempre pode tê-los chamar um método comum (templated).
template <typename T>
Complex complex_mult_impl(T const& lhs, Complex const& rhs) { ... } // Note (1)
// return type is not 'Complex const', see (2)
Complex operator*(int lhs, Complex const& rhs)
{
return complex_mult_impl(lhs,rhs);
}
Mas se você usar Boost.operators só fornecer Complexo :: operator * = (int) e Complexo :: operator * = (double) e as versões autônomas será automaticamente deduzido:)
(1) Você pode usar passagem por valor aqui, se todos os argumentos são construídos-ins. Você também pode querer considerar Boost.CallTraits , que escolhe automaticamente entre por valor e por-ref dependendo se o argumento é built-in ou não. É útil para modelos.
(2) Ao retornar argumentos por valor, é não-sensical para qualificá-los como const
. A palavra-chave const
só significa algo para referências e ponteiros, aqui, evita que nada o usuário instanciar um Complex
'simples' ... e você está feliz que não!
Outras dicas
Você poderia fazer tanto o real ou classe Complex tem operadores de multiplicação não globais.
class Real
{
........
template <class T> const Real operator*(const T&);
const Real operator*(const Real&);
};
Você pode fazer construtores complexos explícita? Isto significa que a conversão implícita de real de Complexo não é permitido e deve disambiguate o operador *