Błąd kompilatora C2666

"identifier" : przeciążenia liczbowe mają podobne konwersje

Przeciążona funkcja lub operator jest niejednoznaczna. Formalne listy parametrów mogą być zbyt podobne dla kompilatora, aby rozwiązać niejednoznaczność. Aby rozwiązać ten błąd, jawnie rzutuj jeden lub więcej rzeczywistych parametrów.

Przykłady

Poniższy przykład generuje C2666:

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

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

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

Ten błąd można wygenerować w wyniku pracy dotyczącej zgodności kompilatora, która została wykonana dla programu Visual Studio 2019 w wersji 16.1:

  • Konwersja, która promuje wyliczenie, którego typ bazowy jest stały dla jego typu bazowego, jest lepszy niż taki, który promuje promowany typ bazowy, jeśli te dwa są różne.

W poniższym przykładzie pokazano, jak zmienia się zachowanie kompilatora w programie Visual Studio 2019 w wersji 16.1 lub nowszej:

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

Ten błąd można również wygenerować w wyniku pracy kompilatora, która została wykonana dla programu Visual Studio .NET 2003:

  • operatory binarne i konwersje zdefiniowane przez użytkownika na typy wskaźników

  • konwersja kwalifikacji nie jest taka sama jak konwersja tożsamości

Dla operatorów <binarnych , <>, = i >=, przekazany parametr jest teraz niejawnie konwertowany na typ operandu, jeśli typ parametru definiuje operatora konwersji zdefiniowanego przez użytkownika, aby przekonwertować na typ operandu. Obecnie istnieje potencjał niejednoznaczności.

W przypadku kodu, który jest prawidłowy zarówno w wersjach Visual Studio .NET 2003, jak i Visual Studio .NET visual C++, wywołaj operatora klasy jawnie przy użyciu składni funkcji.

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

Poniższy przykład generuje 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);
    }
};