Delen via


Compilerfout C2440

'initialiseren': kan niet converteren van 'type1' naar 'type2'
'conversie': kan niet converteren van 'type1' naar 'type2'

Opmerkingen

De compiler kan niet impliciet converteren van type1 naar type2, of kan de opgegeven cast- of conversieoperator niet gebruiken.

De compiler genereert C2440 wanneer hij een type niet kan omzetten naar een ander type, hetzij impliciet, hetzij door de opgegeven cast- of conversieoperator te gebruiken. Er zijn veel manieren om deze fout te genereren. In de sectie Voorbeelden hebben we een aantal algemene items vermeld.

Voorbeelden

Letterlijke tekenreeksen van C++ zijn const

C2440 kan worden veroorzaakt als u probeert een niet-constchar* (of wchar_t*) te initialiseren door een letterlijke tekenreeks te gebruiken in C++-code, wanneer de optie /Zc:strictStrings voor compilerconformiteit is ingesteld. In C is het type van een letterlijke tekenreeks een array van char, maar in C++ is het een array van const char. In dit voorbeeld wordt C2440 gegenereerd:

// 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-literalen u8 zijn const char8_t

In C++20 of onder /Zc:char8_t is een letterlijke UTF-8-teken of tekenreeks (zoals u8'a' of u8"String") van het type const char8_t of const char8_t[N], respectievelijk. In dit voorbeeld ziet u hoe het compilergedrag verandert tussen C++17 en 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
}

Aanwijzer naar lid

Mogelijk ziet u C2440 als u een aanwijzer naar lid probeert te void*converteren. In het volgende voorbeeld wordt C2440 gegenereerd:

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

Cast van niet-gedefinieerd type

De compiler emiteert C2440 als u probeert te casten van een type dat alleen vooruit is gedeclareerd maar niet gedefinieerd. In dit voorbeeld wordt C2440 gegenereerd:

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

Niet-compatibele oproepconventie

De C2440-fouten op regel 15 en 16 van het volgende voorbeeld worden gekwalificeerd met het Incompatible calling conventions for UDT return value bericht. Een UDT is een door de gebruiker gedefinieerd type, zoals een klasse, structof samenvoeging. Dit soort incompatibiliteitsfouten worden veroorzaakt wanneer de aanroepconventie van een UDT die is opgegeven in het retourtype van een doorstuurdeclaratie een conflict veroorzaakt met de werkelijke aanroepconventie van de UDT en wanneer een functieaanwijzer wordt betrokken.

In het voorbeeld zijn er eerst voorwaartse declaraties voor een struct en voor een functie die de struct retourneert. De compiler gaat ervan uit dat de struct C++-aanroepconventie wordt gebruikt. Hierna volgt de struct definitie, die standaard gebruikmaakt van de C-aanroepconventie. Omdat de compiler de aanroepconventie van de struct niet kent totdat het volledig de struct heeft gelezen, wordt ervan uitgegaan dat de aanroepconventie voor het struct in het retourtype van get_c2 ook C++ is.

De struct functie wordt gevolgd door een andere functiedeclaratie die de structfunctie retourneert. Op dit moment weet de compiler dat de structaanroepconventie C++ is. Op dezelfde manier wordt de functieaanwijzer, die de structfunctie aanwijst, gedefinieerd na de struct definitie. De compiler weet nu dat de struct C++-aanroepconventie wordt gebruikt.

Als u C2440-fouten wilt oplossen die worden veroorzaakt door incompatibele aanroepende conventies, declareert u functies die een UDT retourneren na de UDT-definitie.

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

Nul toewijzen aan binnenste aanwijzer

C2440 kan ook optreden als u nul toewijst aan een binnenaanwijzer:

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

Door de gebruiker gedefinieerde conversies

C2440 kan ook optreden voor een onjuist gebruik van een door de gebruiker gedefinieerde conversie. Wanneer bijvoorbeeld een conversieoperator is gedefinieerd als explicit, kan de compiler deze niet gebruiken in een impliciete conversie. Zie User-Defined Conversies (C++/CLI)) voor meer informatie over door de gebruiker gedefinieerde conversies. In dit voorbeeld wordt C2440 gegenereerd:

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

C2440 kan ook optreden als u probeert een exemplaar van een matrix te maken in C++/CLI waarvan het type een Arrayis. Zie Matrices voor meer informatie. In het volgende voorbeeld wordt C2440 gegenereerd:

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

Kenmerken

C2440 kan ook optreden vanwege wijzigingen in de kenmerkfunctie. In het volgende voorbeeld wordt C2440 gegenereerd.

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

Uitbreidingen van componenten naar beneden typeconversies

Met de Microsoft C++-compiler kan de const_cast operator geen cast-conversie meer uitvoeren wanneer u broncode compileert onder /clr.

Gebruik de juiste cast-operator om de fout C2440 op te lossen. Zie Cast-operators voor meer informatie.

In dit voorbeeld wordt C2440 gegenereerd:

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

Wijzigingen in overeenstemming met sjabloonmatching

C2440 kan optreden vanwege wijzigingen in de conformiteit van de compiler in Visual Studio 2015 Update 3. Voorheen behandelde de compiler bepaalde afzonderlijke expressies onjuist als hetzelfde type bij het identificeren van een sjabloonovereenkomst voor een static_cast bewerking. De compiler onderscheidt nu de typen correct en code die afhankelijk is van het vorige static_cast gedrag, is verbroken. Als u dit probleem wilt oplossen, wijzigt u het sjabloonargument zodat dit overeenkomt met het sjabloonparametertype, of gebruikt u een reinterpret_cast-cast of een C-stijlcast.

In dit voorbeeld wordt C2440 gegenereerd:

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

Deze fout kan worden weergegeven in ATL-code die gebruikmaakt van de SINK_ENTRY_INFO macro die is gedefinieerd in <atlcom.h>.

Copy-lijst-initialisatie

Visual Studio 2017 en hoger genereert compilerfouten met betrekking tot het maken van objecten met behulp van initialisatielijsten. Deze fouten zijn niet onderschept in Visual Studio 2015 en kunnen leiden tot crashes of niet gedefinieerd runtime-gedrag. In C++17 copy-list-initialisatie moet de compiler rekening houden met een expliciete constructor voor overbelastingsresolutie, maar moet er een fout optreden als die overbelasting daadwerkelijk is gekozen.

In het volgende voorbeeld wordt gecompileerd in Visual Studio 2015, maar niet in 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 &'
}

Gebruik directe initialisatie om de fout te corrigeren:

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

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

cv-kwalificatie in klassebouw

In Visual Studio 2015 negeert de compiler soms ten onrechte de cv-kwalificatie bij het genereren van een klasseobject via een constructor-aanroep. Dit defect kan leiden tot een crash of onverwacht runtimegedrag. In het volgende voorbeeld wordt gecompileerd in Visual Studio 2015, maar wordt een compilerfout gegenereerd in Visual Studio 2017 en hoger:

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

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

Als u de fout wilt corrigeren, declareert u operator int() als const.