Pergunta

Eu estou tendo um comportamento estranho com uma sobrecarga de operador em C ++. Eu tenho uma classe, e eu preciso verificar se seu conteúdo é maior ou igual a um long double. Eu sobrecarregado o> = operador para fazer esta verificação, a minha declaração é a seguinte:

bool MyClass::operator>=(long double value) const;

Eu tenho que dizer que eu também tenho um operador de conversão-a-long-duplo para minha classe, que funciona sem exceções apenas sob certas condições. Agora, quando eu usar este operador, o compilador reclama que há um uso ambíguo de operador> = e as alternativas são:

  • Mina.
  • A built-in operator>=(long double, int).

Agora, como faço para forçar o programa para usar o meu operador?

Foi útil?

Solução

2015 atualização: Ou, se você quiser manter a capacidade de conversão usando a sintaxe (double)obj vez a sintaxe obj.to_double(), fazer a função de conversão explicit prefixando-lo com essa palavra-chave. Você precisa de uma conversão explícita, em seguida, para a conversão de gatilho. Pessoalmente, eu prefiro a sintaxe .to_double, a menos que a conversão seria bool porque, nesse caso, a conversão é usado por if(obj) mesmo que seja explicit, e que é consideravelmente mais legível do que if(obj.to_bool()) na minha opinião.


Retirar o operador de conversão. Ele vai causar problemas por todo o caminho. Tem uma função como

to_double()

ou similar que os retornos da dupla valor e chamar essa função explicitamente para obter um duplo.

Para o problema em questão, não há esse problema:

obj >= 10

Considere essa expressão. O operador incorporado coincide com o primeiro argumento de conversão por uma sequência definida de utilizador para o seu tipo utilizando o operador de conversão de comprimento duplo (). Mas a sua função corresponde ao segundo argumento por uma seqüência de conversão padrão de int para long double (integral à conversão de ponto flutuante). É sempre ambígua quando há conversões para dois argumentos, mas não pelo menos um argumento que pode ser convertido melhor, enquanto os restantes argumentos não são convertidos pior para uma chamada. No seu caso, o embutida corresponde ao segundo argumento melhor, mas o primeiro pior, mas a sua função corresponde ao primeiro argumento melhor, mas o segundo pior.

É confuso, então aqui estão alguns exemplos (conversões de char para int são chamados de promoções, que são melhores do que as conversões de char para algo diferente de int, que é chamado uma conversão):

void f(int, int);
void f(long, long);
f('a', 'a');

Chama a primeira versão. Porque todos os argumentos para o primeiro pode ser convertido melhor. Igualmente, o seguinte ainda vai chamar o primeiro:

void f(int, long);
void f(long, long);
f('a', 'a');

Uma vez que o primeiro pode ser convertido melhor, eo segundo não é convertido pior. Mas o seguinte é ambígua :

void f(char, long);
void f(int, char);
f('a', 'a'); // ambiguous

É mais interessante neste caso. A primeira versão aceita o primeiro argumento por uma correspondência exata. A segunda versão aceita o segundo argumento por uma correspondência exata. Mas ambas as versões não aceitar o seu outro argumento, pelo menos, igualmente bem. A primeira versão requer uma conversão para seu segundo argumento, enquanto a segunda versão requer uma promoção para seu argumento. Assim, mesmo que uma promoção é melhor do que uma conversão, a chamada para a segunda versão falhar.

É muito semelhante ao seu caso acima. Mesmo que uma seqüência de conversão padrão (conversão de int / float / double de long double) é melhor do que uma seqüência de conversão definida pelo usuário (conversão de MyClass para long double), sua versão operador não é escolhido, porque o seu outro parâmetro (long double) requer uma conversão a partir do argumento que é pior do que o que as necessidades do operador integrado para que o argumento (combinação perfeita).

Resolução de sobrecarga é um assunto complexo em C ++, para que se possa impossivelmente lembrar de todas as regras sutis na mesma. Mas recebendo o plano áspero é bastante possível. Espero que ajude você.

Outras dicas

Ao fornecer uma conversão implícita a um double você está efetivamente dizendo, minha classe é equivalente a uma double e por isso você não deve realmente importa se o construído em operador> = para doubles é usado. Se você do cuidado, em seguida, sua classe realmente não é 'equivalente' a uma double e você não deve considerar a possibilidade de um implícita conversão para double, mas em vez fornecendo um explícita GetAsDouble ou função membro ConvertToDouble.

A razão que você tem uma ambigüidade no momento é que, para um t >= d expressão onde t é uma instância de sua classe e d é um duplo, o compilador sempre tem de fornecer uma conversão, quer do lado esquerdo ou o direito lado de modo a expressão realmente é ambíguo. t quer de operator double é chamado e as built-in operador> = para doubles é usado, ou d deve ser promovido a um long double e seu operador de membro> = é usado.

Editar, você atualizou sua pergunta para sugerir que sua conversão é longo casal e sua comparação é contra um int. Caso em que o último parágrafo deve ler-se:

A razão que você tem uma ambigüidade no momento é que, para um t >= d expressão onde t é uma instância de sua classe e d é um int, o compilador sempre tem de fornecer uma conversão, quer do lado esquerdo ou o direito lado de modo a expressão realmente é ambíguo. t quer de operator long double é chamado e as built-in operador> = para long double e int é usado, ou d deve ser promovido a um long double e seu operador de membro> = é usado.

Eu suponho que você está comparando contra um int literal, e não um long double:

MyClass o;

if (o >= 42)
{
   // ...
}

Se for esse o caso, ambas as alternativas são como bom / complexa.

Usando o seu operator long double():

  1. MyClass::operator long double()
  2. built-in operator>=(long double, int)

Usando o seu MyClass::operator>=(long double):

  1. built-in de conversão int para long double
  2. MyClass::operator>=(long double)

Você tem long double na declaração. Tente mudá-lo para double.

O uso de sobrecarga de operador combinado com fundição personalizado pode ser muito confuso para os usuários de sua classe. Pergunte a si mesmo, que os usuários desta classe esperar -lo para converter-se em um duplo, ou seja comparável com um duplo? não tendo uma função .greaterThan (duplo) atingir o mesmo objetivo, mas sem surpreender o usuário?

Eu acho que você poderia sempre converter explicitamente o objeto para dobrar antes de comparar, para evitar a ambiguidade. Mas se eu fosse você eu reconsiderar a abordagem acima e se concentrar em escrever código que é intuitivo e se comporta de forma surpreendente, em vez de fantasia tipo de fundição e sobrecarga de operadores.

(Inspirado pelo maravilhoso discurso retórico sobre sobrecarga de operador da FQA )

  • A built-in operador> = (long double, int).

Parece que você definido:

bool class::operator>=(long double value) { return value >= classValue; }

E você está faltando:

bool class::operator>=(double value)      { return value >= classValue; }
bool class::operator>=(int value)         { return value >= classValue; }

Assim, o compilador não pode decidir qual o caminho a converso. (É ambíguo.)

Talvez uma função templated (ou método) seria útil?

Cuidado com as situações em que a> = b invoca métodos diferentes de b> = a .

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top