Ошибка компилятора C2440
"инициализация": не удается преобразовать из типа1 в "type2"
"преобразование": не удается преобразовать из типа1 в "type2"
Компилятор не может неявно преобразовывать из *type1*
*type2*
нее или не может использовать указанный оператор приведения или преобразования.
Замечания
Компилятор создает C2440, если он не может преобразоваться из одного типа в другой, неявно или с помощью указанного оператора приведения или преобразования. Существует множество способов создания этой ошибки. В разделе "Примеры" перечислены некоторые распространенные.
Примеры
Строковые литералы C++: const
C2440 может быть вызван при попытке инициализации не-constchar*
(или wchar_t*
) с помощью строкового литерала в коде C++ при установке параметра /Zc:strictStrings
соответствия компилятора. В C тип строкового литерала является массивом char
, но в C++, это массив const char
. В этом примере создается 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 u8
const char8_t
В C++20 или в нижней /Zc:char8_t
части символ или строка UTF-8 (например u8'a'
u8"String"
, или) имеет тип const char8_t
или const char8_t[N]
соответственно. В этом примере показано, как изменяется поведение компилятора между C++17 и 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
}
Указатель на член
Если вы пытаетесь преобразовать указатель в элемент void*
, может отображаться C2440. Следующий пример создает 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);
}
};
Приведение неопределенного типа
Компилятор выдает C2440 при попытке приведения из типа, который объявлен только вперед, но не определен. В этом примере создается 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 *'
}
Несовместимое соглашение о вызовах
Ошибки C2440 в строках 15 и 16 следующего примера квалифицированы с сообщением Incompatible calling conventions for UDT return value
. Определяемый пользователем тип — это определяемый пользователем тип, например класс или structобъединение. Эти типы ошибок несовместимости возникают при возникновении соглашения о вызове определяемого пользователем типа, указанного в возвращаемом типе объявления пересылки, конфликтует с фактическим соглашением о вызове определяемого пользователем типа и при использовании указателя функции.
В примере сначала есть объявления пересылки для функции struct , возвращающей объект struct. Компилятор предполагает, что struct используется соглашение о вызовах C++. Далее — struct определение, которое использует соглашение о вызовах C по умолчанию. Так как компилятор не знает соглашение struct о вызове до тех пор, пока он не завершит чтение всего struct, соглашение о вызове для struct возвращаемого типа get_c2
также считается C++.
За ним следует другое struct объявление функции, возвращающее structзначение . На этом этапе компилятор знает, что structсоглашение о вызове — C++. Аналогичным образом указатель функции, возвращающий structобъект, определяется после struct определения. Компилятор теперь знает struct , что использует соглашение о вызовах C++.
Чтобы устранить ошибки C2440, вызванные несовместимыми соглашениями о вызовах, объявите функции, возвращающие 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
}
Назначение нулю внутреннему указателю
C2440 также может произойти, если вы назначаете ноль внутреннему указателю:
// 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
}
Пользовательские преобразования
C2440 также может возникать для неправильного использования определяемого пользователем преобразования. Например, если оператор преобразования определен как explicit
, компилятор не может использовать его в неявном преобразовании. Дополнительные сведения о пользовательских преобразованиях см. в разделе "Определяемые пользователем преобразования" (C++/CLI)). В этом примере создается 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
создание
C2440 также может возникать, если вы пытаетесь создать экземпляр массива в C++/CLI, тип которого является.Array Дополнительные сведения см. в статье Arrays (C++/CLI and C++/CX) (Массивы (C++/CLI и C++/CX)). Следующий пример создает 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));
}
Атрибуты
C2440 также может возникать из-за изменений в функции атрибутов. В следующем примере возникает ошибка C2440.
// c2440f.cpp
// compile with: /LD
[ module(name="PropDemoLib", version=1.0) ]; // C2440
// try the following line instead
// [ module(name="PropDemoLib", version="1.0") ];
Расширения компонентов вниз приведения
Компилятор Microsoft C++ больше не позволяет const_cast
оператору выполнять приведение при компиляции исходного кода в разделе /clr
.
Чтобы устранить эту проблему C2440, используйте правильный оператор приведения. Дополнительные сведения см. в разделе "Операторы приведения".
В этом примере создается 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
}
Соответствие изменений в соответствии с шаблоном
C2440 может возникать из-за изменений соответствия компилятору в Visual Studio 2015 с обновлением 3. Ранее компилятор неправильно обрабатывал определенные отдельные выражения с тем же типом при определении соответствия шаблона для static_cast
операции. Теперь компилятор правильно различает типы, а код, зависящий от предыдущего static_cast
поведения, нарушается. Чтобы устранить эту проблему, измените аргумент шаблона на соответствие типу параметра шаблона или используйте reinterpret_cast
приведение в стиле C.
В этом примере создается 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);
}
Эта ошибка может появиться в коде ATL, использующего макрос, определенный SINK_ENTRY_INFO
в <atlcom.h>
.
Инициализация копии списка
Visual Studio 2017 и более поздних версий правильно вызывают ошибки компилятора, связанные с созданием объектов с помощью списков инициализаторов. Эти ошибки не были пойманы в Visual Studio 2015 и могут привести к сбоям или неопределенному поведению среды выполнения. В C++17 copy-list-initialization компилятор должен рассмотреть явный конструктор для разрешения перегрузки, но должен вызвать ошибку, если эта перегрузка на самом деле выбрана.
Следующий пример компилируется в Visual Studio 2015, но не в 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 &'
}
Чтобы исправить эту ошибку, следует использовать прямую инициализацию:
// C2440k.cpp
struct A
{
explicit A(int) {}
A(double) {}
};
int main()
{
const A& a2{ 1 };
}
CV-квалификаторы при построении класса
В Visual Studio 2015 компилятор иногда ошибочно игнорирует cv-квалификатор при создании объекта класса путем вызова конструктора. Этот дефект может привести к сбою или непредвиденному поведению среды выполнения. Следующий пример компилируется в Visual Studio 2015, но вызывает ошибку компилятора в Visual Studio 2017 и более поздних версиях:
struct S
{
S(int);
operator int();
};
int i = (const S)0; // error C2440
Чтобы исправить ошибку, объявите оператор int() как const.