Ошибка компилятора C2666

"идентификатор": перегрузки чисел имеют аналогичные преобразования

Перегруженная функция или оператор неоднозначны. Формальные списки параметров могут быть слишком похожими для компилятора, чтобы устранить неоднозначность. Чтобы устранить эту ошибку, явно приведение одного или нескольких фактических параметров.

Примеры

Следующий пример приводит к возникновению ошибки C2666:

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

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

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

Эта ошибка может быть создана в результате работы соответствия компилятора, выполненной для Visual Studio 2019 версии 16.1:

  • Преобразование, которое приводит перечисление с фиксированным базовым типом к его базовому типу, лучше, чем то, которое приводит перечисление к повышенному базовому типу, если они различаются.

В следующем примере показано, как изменяется поведение компилятора в Visual Studio 2019 версии 16.1 и более поздних версиях:

#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{});
}

Эта ошибка также может быть создана в результате работы соответствия компилятора, которая была выполнена для Visual Studio .NET 2003:

  • двоичные операторы и определяемые пользователем преобразования в типы указателей

  • Преобразование квалификации не совпадает с преобразованием удостоверений

Для двоичных операторов <, <>=и >=переданный параметр теперь неявно преобразуется в тип операнда, если тип параметра определяет определяемый пользователем оператор преобразования для преобразования в тип операнда. В настоящее время существует потенциал неоднозначности.

Для кода, допустимого как в visual Studio .NET 2003, так и в версиях Visual Studio .NET Visual C++, вызовите оператор класса явным образом с помощью синтаксиса функции.

// 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");
}

Следующий пример создает 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);
    }
};