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 u8
są const char8_t
W języku C++20 lub w obszarze /Zc:char8_t
znak 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.