Błąd kompilatora C2440

"inicjowanie" : nie można przekonwertować z "type1" na "type2"
"konwersja" : nie można przekonwertować z "type1" na "type2"

Kompilator nie może niejawnie konwertować z *type1* na *type2*, ani nie może użyć określonego operatora rzutowania lub konwersji.

Uwagi

Kompilator generuje C2440, gdy nie może przekonwertować z jednego typu na inny, niejawnie lub przy użyciu określonego operatora rzutowania lub konwersji. Istnieje wiele sposobów generowania tego błędu. W sekcji Przykłady wymieniono niektóre typowe z nich.

Przykłady

Literały ciągu języka C++ to const

C2440 może być spowodowany próbą zainicjowania elementu innegoconstchar* niż (lub wchar_t*) przy użyciu literału ciągu w kodzie języka C++, gdy jest ustawiona opcja /Zc:strictStrings zgodności kompilatora. W języku C typ literału ciągu to tablica char, ale w języku C++, jest to tablica const char. Ten przykład generuje C2440:

// C2440s.cpp
// Build: cl /Zc:strictStrings /W3 C2440s.cpp
// When built, the compiler emits:
// error C2440: 'initializing' : cannot convert from 'const char [5]'
// to 'char *'
//        Conversion from string literal loses const qualifier (see
// /Zc:strictStrings)

int main() {
   char* s1 = "test"; // C2440
   const char* s2 = "test"; // OK
}

Literały języka C++20 u8const char8_t

W języku C++20 lub w obszarze /Zc:char8_tznak literału UTF-8 lub ciąg (np u8'a' . lub u8"String") jest odpowiednio typu const char8_t lub const char8_t[N]. W tym przykładzie pokazano, jak zmienia się zachowanie kompilatora między językami C++17 i C++20:

// C2440u8.cpp
// Build: cl /std:c++20 C2440u8.cpp
// When built, the compiler emits:
// error C2440: 'initializing' : cannot convert from 'const char8_t [5]'
// to 'const char *'
// note: Types pointed to are unrelated; conversion requires
// reinterpret_cast, C-style cast or function-style cast)

int main() {
   const char* s1 = u8"test"; // C2440 under /std:c++20 or /Zc:char8_t, OK in C++17
   const char8_t* s2 = u8"test"; // OK under /std:c++20 or /Zc:char8_t, C4430 in C++17
   const char* s3 = reinterpret_cast<const char*>(u8"test"); // OK
}

Wskaźnik do elementu członkowskiego

Jeśli próbujesz przekonwertować wskaźnik na element członkowski void*, może zostać wyświetlony komunikat C2440. Następny przykład generuje C2440:

// C2440.cpp
class B {
public:
   void  f(){;}

   typedef void (B::*pf)();

   void f2(pf pf) {
       (this->*pf)();
       void* pp = (void*)pf;   // C2440
   }

   void f3() {
      f2(f);
   }
};

Rzutowanie niezdefiniowanego typu

Kompilator emituje C2440, jeśli próbujesz rzutować z typu, który jest zadeklarowany tylko do przodu, ale nie jest zdefiniowany. Ten przykład generuje C2440:

// c2440a.cpp
struct Base { }; // Defined

struct Derived; // Forward declaration, not defined

Base * func(Derived * d) {
    return static_cast<Base *>(d); // error C2440: 'static_cast' : cannot convert from 'Derived *' to 'Base *'
}

Niezgodna konwencja wywoływania

Błędy C2440 w wierszach 15 i 16 następnego przykładu są kwalifikowane z komunikatem Incompatible calling conventions for UDT return value . UdT jest typem zdefiniowanym przez użytkownika, takim jak klasa, structlub union. Tego rodzaju błędy niezgodności są spowodowane podczas wywoływania konwencji UDT określonej w zwracanym typie deklaracji przekazywania powoduje konflikt z rzeczywistą konwencją wywołania udT i gdy jest zaangażowany wskaźnik funkcji.

W tym przykładzie najpierw istnieją deklaracje przesyłania dalej dla funkcji struct i, która zwraca structwartość . Kompilator zakłada, że struct program używa konwencji wywoływania języka C++. Następnie jest struct definicja, która domyślnie używa konwencji wywoływania języka C. Ponieważ kompilator nie zna konwencji wywoływania elementu struct , dopóki nie zakończy odczytywania całego structelementu , przyjmuje się również, że jako C++przyjmuje się konwencję struct wywoływania elementu w zwracanym typie get_c2 .

Następuje struct po nim inna deklaracja funkcji zwracająca structwartość . W tym momencie kompilator wie, że structkonwencja wywoływania to C++. Podobnie wskaźnik funkcji, który zwraca structwartość , jest zdefiniowany po struct definicji. Kompilator zna teraz konwencję struct wywoływania języka C++.

Aby usunąć błędy C2440 spowodowane niezgodnymi konwencjami wywoływania, zadeklaruj funkcje zwracające funkcję UDT po definicji UDT.

// C2440b.cpp
struct MyStruct;

MyStruct get_c1();

struct MyStruct {
   int i;
   static MyStruct get_C2();
};

MyStruct get_C3();

typedef MyStruct (*FC)();

FC fc1 = &get_c1;   // C2440, line 15
FC fc2 = &MyStruct::get_C2;   // C2440, line 16
FC fc3 = &get_C3;

class CMyClass {
public:
   explicit CMyClass( int iBar)
      throw()   {
   }

   static CMyClass get_c2();
};

int main() {
   CMyClass myclass = 2;   // C2440
   // try one of the following
   // CMyClass myclass{2};
   // CMyClass myclass(2);

   int *i;
   float j;
   j = (float)i;   // C2440, cannot cast from pointer to int to float
}

Przypisywanie zera do wskaźnika wewnętrznego

C2440 może również wystąpić, jeśli przypiszesz zero do wskaźnika wewnętrznego:

// C2440c.cpp
// compile with: /clr
int main() {
   array<int>^ arr = gcnew array<int>(100);
   interior_ptr<int> ipi = &arr[0];
   ipi = 0;   // C2440
   ipi = nullptr;   // OK
}

Konwersje zdefiniowane przez użytkownika

C2440 może również wystąpić w przypadku nieprawidłowego użycia konwersji zdefiniowanej przez użytkownika. Na przykład gdy operator konwersji został zdefiniowany jako explicit, kompilator nie może go użyć w niejawnej konwersji. Aby uzyskać więcej informacji na temat konwersji zdefiniowanych przez użytkownika, zobacz Konwersje zdefiniowane przez użytkownika (C++/CLI)). Ten przykład generuje C2440:

// C2440d.cpp
// compile with: /clr
value struct MyDouble {
   double d;
   // convert MyDouble to Int32
   static explicit operator System::Int32 ( MyDouble val ) {
      return (int)val.d;
   }
};

int main() {
   MyDouble d;
   int i;
   i = d;   // C2440
   // Uncomment the following line to resolve.
   // i = static_cast<int>(d);
}

System::Array Tworzenia

C2440 może również wystąpić, jeśli spróbujesz utworzyć wystąpienie tablicy w języku C++/cli, którego typem Arrayjest . Aby uzyskać więcej informacji, zobacz Tablice. Następny przykład generuje C2440:

// C2440e.cpp
// compile with: /clr
using namespace System;
int main() {
   array<int>^ intArray = Array::CreateInstance(__typeof(int), 1);   // C2440
   // try the following line instead
   // array<int>^ intArray = safe_cast<array<int> ^>(Array::CreateInstance(__typeof(int), 1));
}

Atrybuty

C2440 może również wystąpić z powodu zmian w funkcji atrybutów. Poniższy przykład generuje kod C2440.

// c2440f.cpp
// compile with: /LD
[ module(name="PropDemoLib", version=1.0) ];   // C2440
// try the following line instead
// [ module(name="PropDemoLib", version="1.0") ];

Rzutowanie rozszerzeń składników w dół

Kompilator języka Microsoft C++ nie zezwala już operatorowi na odrzucanie rzutowania podczas kompilowania kodu źródłowego const_cast w obszarze /clr.

Aby rozwiązać ten problem c2440, użyj poprawnego operatora rzutowania. Aby uzyskać więcej informacji, zobacz Operatory rzutów.

Ten przykład generuje C2440:

// c2440g.cpp
// compile with: /clr
ref class Base {};
ref class Derived : public Base {};
int main() {
   Derived ^d = gcnew Derived;
   Base ^b = d;
   d = const_cast<Derived^>(b);   // C2440
   d = dynamic_cast<Derived^>(b);   // OK
}

Zgodne zmiany dopasowania szablonu

C2440 może wystąpić z powodu zmian zgodności kompilatora w programie Visual Studio 2015 Update 3. Wcześniej kompilator nieprawidłowo potraktował pewne odrębne wyrażenia co ten sam typ podczas identyfikowania dopasowania szablonu do static_cast operacji. Teraz kompilator prawidłowo rozróżnia typy, a kod, który polegał na poprzednim static_cast zachowaniu, jest uszkodzony. Aby rozwiązać ten problem, zmień argument szablonu, aby był zgodny z typem parametru szablonu lub użyj reinterpret_cast rzutowania w stylu C.

Ten przykład generuje C2440:

// c2440h.cpp

template<int *a>
struct S1 {};

int g;
struct S2 : S1<&g> {
};

int main()
{
    S2 s;
    static_cast<S1<&*&g>>(s); // C2440 in VS 2015 Update 3
    // This compiles correctly:
    // static_cast<S1<&g>>(s);
}

Ten błąd może pojawić się w kodzie ATL, który używa makra zdefiniowanego SINK_ENTRY_INFO w pliku <atlcom.h>.

Inicjowanie listy kopiowania

Program Visual Studio 2017 lub nowszy prawidłowo zgłasza błędy kompilatora związane z tworzeniem obiektów przy użyciu list inicjatora. Te błędy nie zostały przechwycone w programie Visual Studio 2015 i mogą prowadzić do awarii lub niezdefiniowanego zachowania środowiska uruchomieniowego. W przypadku inicjowania kopii listy C++17 kompilator jest wymagany do rozważenia jawnego constructlub przeciążonego rozwiązania, ale w przypadku wybrania tego przeciążenia musi zgłosić błąd.

Poniższy przykład kompiluje się w programie Visual Studio 2015, ale nie w programie Visual Studio 2017.

// C2440j.cpp
struct A
{
    explicit A(int) {}
    A(double) {}
};

int main()
{
    const A& a2 = { 1 }; // error C2440: 'initializing': cannot
                         // convert from 'int' to 'const A &'
}

Aby naprawić błąd, użyj bezpośredniej inicjalizacji:

// C2440k.cpp
struct A
{
    explicit A(int) {}
    A(double) {}
};

int main()
{
    const A& a2{ 1 };
}

kwalifikatory cv w jonie klasy construct

W programie Visual Studio 2015 kompilator czasami niepoprawnie ignoruje kwalifikator cv podczas generowania obiektu klasy za pośrednictwem constructwywołania lub . Ta usterka może potencjalnie spowodować awarię lub nieoczekiwane zachowanie środowiska uruchomieniowego. Poniższy przykład kompiluje się w programie Visual Studio 2015, ale zgłasza błąd kompilatora w programie Visual Studio 2017 lub nowszym:

struct S
{
    S(int);
    operator int();
};

int i = (const S)0; // error C2440

Aby poprawić błąd, zadeklaruj operator int() jako const.