Kompilatorfel C2440

"initializing" : kan inte konvertera från 'type1' till 'type2'
"konvertering" : kan inte konvertera från "type1" till "type2"

Anmärkningar

Kompilatorn kan inte implicit konvertera från type1 till type2eller kan inte använda den angivna cast- eller konverteringsoperatorn.

Kompilatorn genererar C2440 när den inte kan konvertera från en typ till en annan, antingen implicit eller med hjälp av den angivna cast- eller konverteringsoperatorn. Det finns många sätt att generera det här felet. Vi har listat några vanliga i avsnittet Exempel.

Exempel

C++-strängliteraler är const

C2440 kan orsakas om du försöker initiera en icke-constchar* (eller wchar_t*) med hjälp av en strängliteral i C++-kod när kompilatorkonformitetsalternativet /Zc:strictStrings har angetts. I C är typen av en strängliteral matris av char, men i C++ är det matris av const char. Det här exemplet genererar 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
}

C++20-literaler u8 är const char8_t

I C++20 eller under /Zc:char8_tär ett UTF-8-literaltecken eller sträng (till exempel u8'a' eller u8"String") av typen const char8_t eller const char8_t[N]. Det här exemplet visar hur kompilatorbeteendet ändras mellan C++17 och 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
}

Pekare till medlem

Du kan se C2440 om du försöker konvertera en pekare till medlem till void*. Nästa exempel genererar 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);
   }
};

Gjutning av odefinierad typ

Kompilatorn genererar C2440 om du försöker konvertera från en typ som endast är förklarad i förväg men inte definierad. Det här exemplet genererar 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 *'
}

Inkompatibel samtalskonvention

C2440-felen på raderna 15 och 16 i nästa exempel är kvalificerade med meddelandet Incompatible calling conventions for UDT return value . En UDT är en användardefinierad typ, till exempel en klass, structeller union. Den här typen av inkompatibilitetsfel orsakas när anropskonventionen för en UDT som anges i returtypen för en framåtdeklaration står i konflikt med UDT:s faktiska anropskonvention och när en funktionspekare ingår.

I exemplet finns det först framåtdeklarationer för en struct och för en funktion som returnerar struct. Kompilatorn förutsätter att struct använder C++-anropskonventionen. Nästa är struct definitionen, som använder C-anropskonventionen som standard. Eftersom kompilatorn inte känner till anropskonventionen struct förrän den har läst klart hela structantas anropskonventionen för struct i returtypen get_c2 också vara C++.

struct Följs av en annan funktionsdeklaration som returnerar struct. Nu vet kompilatorn att structanropskonventionen är C++. På samma sätt definieras funktionspekaren, som returnerar struct, efter struct definitionen. Kompilatorn känner nu till struct användningskonventionen för C++-anrop.

För att lösa C2440-fel som orsakas av inkompatibla anropskonventioner deklarerar du funktioner som returnerar en UDT efter UDT-definitionen.

// 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
}

Tilldela noll till inre pekare

C2440 kan också inträffa om du tilldelar noll till en inre pekare:

// 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
}

Användardefinierade konverteringar

C2440 kan också inträffa vid felaktig användning av en användardefinierad konvertering. När en konverteringsoperator till exempel har definierats som explicitkan kompilatorn inte använda den i en implicit konvertering. Mer information om användardefinierade konverteringar finns iUser-Defined Konverteringar (C++/CLI)). Det här exemplet genererar 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 skapelse

C2440 kan också inträffa om du försöker skapa en instans av en matris i C++/CLI vars typ är en Array. Mer information finns i Matriser. Nästa exempel genererar 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));
}

Egenskaper

C2440 kan också inträffa på grund av ändringar i attributfunktionen. I följande exempel genereras C2440.

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

Komponenttillägg nedtypekonverteringar

Microsoft C++-kompilatorn tillåter inte längre att operatornconst_cast gör en downcast när du kompilerar källkoden under /clr.

Lös denna C2440 genom att använda rätt gjutningsoperator. För mer information, se Castingoperatorer.

Det här exemplet genererar 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
}

Ändringar för att anpassa mallmatchning

C2440 kan inträffa på grund av överensstämmelseändringar i kompilatorn i Visual Studio 2015 Update 3. Tidigare behandlade kompilatorn felaktigt vissa distinkta uttryck som samma typ när en mallmatchning identifierades för en static_cast åtgärd. Nu särskiljer kompilatorn typerna korrekt och koden som förlitade sig på det tidigare static_cast beteendet är bruten. Åtgärda problemet genom att ändra mallargumentet så att det matchar mallparametertypen, eller använda en reinterpret_cast eller C-formatering.

Det här exemplet genererar 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);
}

Det här felet kan visas i ATL-kod som använder makrot SINK_ENTRY_INFO som definierats i <atlcom.h>.

Kopieringsbaserad listinitiering

Visual Studio 2017 och senare skapar kompilatorfel som är relaterade till att skapa objekt med hjälp av initialiserarlistor. Dessa fel fångades inte i Visual Studio 2015 och kan leda till krascher eller odefinierat körningsbeteende. I C++17 copy-list-initialization måste kompilatorn beakta en explicit konstruktor vid överbelastningslösning, men den måste generera ett fel om den överbelastningen verkligen väljs.

Följande exempel kompileras i Visual Studio 2015 men inte i 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 &'
}

Du kan åtgärda felet genom att använda direktinitiering:

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

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

cv-kvalificerare i klasskonstruktion

I Visual Studio 2015 ignorerar kompilatorn ibland felaktigt cv-qualifier när ett klassobjekt genereras via ett konstruktoranrop. Den här defekten kan potentiellt orsaka en krasch eller oväntat körningsbeteende. Följande exempel kompileras i Visual Studio 2015 men skapar ett kompilatorfel i Visual Studio 2017 och senare:

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

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

Om du vill korrigera felet deklarerar du operatorn int() som const.