Compartilhar via


Erro do compilador C2666

'identifier': sobrecargas numéricas têm conversões semelhantes

Uma função ou operador sobrecarregado é ambíguo. As listas de parâmetros formais podem ser muito semelhantes para o compilador resolver a ambiguidade. Para resolver esse erro, converta explicitamente um ou mais dos parâmetros reais.

Exemplos

O seguinte exemplo gera C2666:

// C2666.cpp
struct complex {
   complex(double);
};

void h(int,complex);
void h(double, double);

int main() {
   h(3,4);   // C2666
}

Esse erro pode ser gerado como resultado do trabalho de conformidade do compilador que foi feito para o Visual Studio 2019 versão 16.1:

  • Uma conversão que promove uma enumeração cujo tipo subjacente é fixado ao seu tipo subjacente é melhor do que uma que promove para o tipo subjacente promovido, se as duas forem diferentes.

O exemplo a seguir demonstra como o comportamento do compilador muda no Visual Studio 2019 versão 16.1 e versões posteriores:

#include <type_traits>

enum E : unsigned char { e };

int f(unsigned int)
{
    return 1;
}

int f(unsigned char)
{
    return 2;
}

struct A {};
struct B : public A {};

int f(unsigned int, const B&)
{
    return 3;
}

int f(unsigned char, const A&)
{
    return 4;
}

int main()
{
    // Calls f(unsigned char) in 16.1 and later. Called f(unsigned int) in earlier versions.
    // The conversion from 'E' to the fixed underlying type 'unsigned char' is better than the
    // conversion from 'E' to the promoted type 'unsigned int'.
    f(e);
  
    // Error C2666. This call is ambiguous, but previously called f(unsigned int, const B&). 
    f(e, B{});
}

Esse erro também pode ser gerado como resultado do trabalho de conformidade do compilador que foi feito para o Visual Studio 2003:

  • operadores binários e conversões definidas pelo usuário em tipos de ponteiro

  • a conversão de qualificação não é a mesma da conversão de identidade

Para os operadores binários<, >, <= e >=, um parâmetro passado será agora convertido implicitamente no tipo do operando se o tipo do parâmetro definir um operador de conversão definido pelo usuário para converter no tipo do operando. Agora há potencial para ambiguidade.

No caso do código válido nas versões do Visual Studio .NET 2003 e do Visual Studio .NET do Visual C++, chame o operador de classe explicitamente usando a sintaxe da função.

// C2666b.cpp
#include <string.h>
#include <stdio.h>

struct T
{
    T( const T& copy )
    {
        m_str = copy.m_str;
    }

    T( const char* str )
    {
        int iSize = (strlen( str )+ 1);
        m_str = new char[ iSize ];
        if (m_str)
            strcpy_s( m_str, iSize, str );
    }

    bool operator<( const T& RHS )
    {
        return m_str < RHS.m_str;
    }

    operator char*() const
    {
        return m_str;
    }

    char* m_str;
};

int main()
{
    T str1( "ABCD" );
    const char* str2 = "DEFG";

    // Error - Ambiguous call to operator<()
    // Trying to convert str1 to char* and then call
    // operator<( const char*, const char* )?
    //  OR
    // trying to convert str2 to T and then call
    // T::operator<( const T& )?

    if( str1 < str2 )   // C2666

    if ( str1.operator < ( str2 ) )   // Treat str2 as type T
        printf_s("str1.operator < ( str2 )\n");

    if ( str1.operator char*() < str2 )   // Treat str1 as type char*
        printf_s("str1.operator char*() < str2\n");
}

O seguinte exemplo gera C2666

// C2666c.cpp
// compile with: /c

enum E
{
    E_A,   E_B
};

class A
{
    int h(const E e) const {return 0; }
    int h(const int i) { return 1; }
    // Uncomment the following line to resolve.
    // int h(const E e) { return 0; }

    void Test()
    {
        h(E_A);   // C2666
        h((const int) E_A);
        h((int) E_A);
    }
};