Pergunta

Eu venho diante de um enigma irritante na minha base de código.Eu não consigo dizer qual o meu código gera este erro, mas (por exemplo) std::string não.

class String {
public:
    String(const char*str);
    friend String operator+ ( const String& lval, const char *rval );
    friend String operator+ ( const char *lval, const String& rval );
    String operator+ ( const String& rval );
};

A implementação destes é fácil o suficiente para imaginar o seu próprio.

Meu programa de driver contém a seguinte:

String result, lval("left side "), rval("of string");
char lv[] = "right side ", rv[] = "of string";
result = lv + rval;
printf(result);
result = (lval + rv);
printf(result);

O que gera o seguinte erro no gcc 4.1.2:

driver.cpp:25: error: ISO C++ says that these are ambiguous, even though the worst conversion for the first is better than the worst conversion for the second:
String.h:22: note: candidate 1: String operator+(const String&, const char*)
String.h:24: note: candidate 2: String String::operator+(const String&)

Até aí tudo bem, certo?Infelizmente, a minha String(const char *str) construtor é tão útil como um construtor implícito, que a utilização explícita de palavras-chave para resolver isso só iria causar um monte de problemas.

Além disso...std::string não ter que recorrer a isso, e eu não consigo descobrir o porquê.Por exemplo, em basic_string.h, eles são declarados da seguinte forma:

template<typename _CharT, typename _Traits, typename _Alloc>
basic_string<_CharT, _Traits, _Alloc>
operator+(const basic_string<_CharT, _Traits, _Alloc>& __lhs,
          const basic_string<_CharT, _Traits, _Alloc>& __rhs)

template<typename _CharT, typename _Traits, typename _Alloc>
basic_string<_CharT,_Traits,_Alloc>
operator+(const _CharT* __lhs,
          const basic_string<_CharT,_Traits,_Alloc>& __rhs);

e assim por diante.O basic_string construtor não é declarado explícito.Como isso não causa o mesmo erro que eu estou recebendo, e como posso obter o mesmo comportamento??

Foi útil?

Solução

O motivo da ambiguidade é que uma função candidata é melhor do que outro candidato funcionar apenas se Nenhum de seus parâmetros são uma correspondência pior do que os parâmetros do outro. Considere suas duas funções:

friend String operator+(const String&, const char*); // (a)
String operator+(const String&);                     // (b)

Você está ligando operator+ com um String e a const char*.

O segundo argumento, do tipo const char*, combina claramente (a) melhor que (b). É uma correspondência exata para (a), mas é necessária uma conversão definida pelo usuário para (b).

Portanto, para que haja uma ambiguidade, o primeiro argumento deve corresponder (b) melhor que (a).

o String no lado esquerdo da chamada para operator+ não é const. Portanto, corresponde (b), que é uma função de membro que não é consultiva, melhor que (a), que leva um const String&.

Portanto, qualquer uma das seguintes soluções removeria a ambiguidade:

  • Mude o membro operator+ ser uma função de membro const
  • Altere o não-membro operator+ para levar um String& em vez de um const String&
  • Ligar operator+ com uma corda const no lado esquerdo

Obviamente, o primeiro, também sugerido por tio, é o melhor caminho a percorrer.

Outras dicas

É suficiente nesse caso, apenas para definir em operator+:

String operator+(const String& lval, const String& rval);

Porque você fornecer um construtor de tomar uma char*, um String pode ser construído a partir de um char* durante a chamada para operator+.Por exemplo:

String hello = "Hello, ";
const char* world = "world!";

String helloWorld = hello + world;

Temporário String vai ser construído com o conteúdo do char* world (porque o construtor não é explícita), em seguida, os dois String os objetos serão passados para operator+.

O erro desaparece se você declarar o membro + const como deveria ser.

class String {
public:
    String(const char*str);
    friend String operator+ ( const String& lval, const char *rval );
    friend String operator+ ( const char *lval, const String& rval );
    String operator+ ( const String& rval ) const; //<-- here
};

Não tenho certeza de qual é o motivo, no entanto. Talvez prefira argumentos vinculativos à referência const, se possível, portanto, a primeira sobrecarga é uma correspondência melhor para o valor esquerdo e a terceira sobrecarga tem uma correspondência melhor para o valor direito.

Melhor explicação. (Deve ter interpretado um pouco o problema.)


printf(result);

Não me diga que sua string tem uma conversão implícita para const char*... isso é mau.

As funções de modelo e não-templos seguem regras diferentes. As funções do modelo são selecionadas nos tipos de parâmetros reais, sem que nenhuma conversa seja aplicada. No caso do não-templado (ou seja, seu código), uma conversão implícita pode ser aplicada. Assim, o material modelo em Basic_String não é ambíguo, mas o seu é.

Você mostrou isso basic_string tem implementações de operator+ correspondendo ao segundo e terceiro operadores em sua classe String. Faz basic_string também tem um operador correspondente ao seu primeiro operador [friend String operator+ ( const String& lval, const char *rval );]?

O que acontece se você remover este operador?

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