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 kreacja

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 C++17 copy-list-initialization kompilator jest wymagany do rozważenia jawnego konstruktora do rozpoznawania przeciążenia, ale musi zgłosić błąd, jeśli to przeciążenie jest rzeczywiście wybrane.

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 konstrukcji klasy

W programie Visual Studio 2015 kompilator czasami niepoprawnie ignoruje kwalifikator cv podczas generowania obiektu klasy za pomocą wywołania konstruktora. 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.