Поделиться через


Ошибка компилятора 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 u8const 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.