컴파일러 오류 C2440

'initializing': 'type1'에서 'type2'로 변환할 수 없습니다.
'conversion': 'type1'에서 'type2'로 변환할 수 없습니다.

컴파일러는 암시적으로 변환 *type1**type2*수 없거나 지정된 캐스트 또는 변환 연산자를 사용할 수 없습니다.

설명

컴파일러는 암시적으로 또는 지정된 캐스트 또는 변환 연산자를 사용하여 한 형식에서 다른 형식으로 변환할 수 없는 경우 C2440을 생성합니다. 이 오류를 생성하는 방법에는 여러 가지가 있습니다. 예제 섹션에 몇 가지 일반적인 항목이 나열되었습니다.

C++ 문자열 리터럴은 다음과 같습니다. const

C2440은 컴파일러 규칙 옵션이 /Zc:strictStrings 설정된 경우 C++ 코드에서 문자열 리터럴을 사용하여 비constchar*(또는wchar_t*) 초기화하려고 할 때 발생할 수 있습니다. 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[N]형식 const char8_t 입니다. 이 샘플에서는 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 *'
}

호환되지 않는 호출 규칙

다음 샘플의 줄 15 및 16에 대한 C2440 오류는 메시지로 Incompatible calling conventions for UDT return value 한정됩니다. UDT는 클래스 struct또는 공용 구조체와 같은 사용자 정의 형식입니다. 이러한 종류의 비호환성 오류는 정방향 선언의 반환 형식에 지정된 UDT의 호출 규칙이 UDT의 실제 호출 규칙과 충돌하고 함수 포인터가 관련될 때 발생합니다.

이 예제에서는 먼저 a 및 함수를 반환하는 함수에 대한 struct 전달 선언이 struct있습니다. 컴파일러는 C++ 호출 규칙을 사용한다고 struct 가정합니다. 다음은 struct 기본적으로 C 호출 규칙을 사용하는 정의입니다. 컴파일러는 전체 struct읽기가 완료될 때까지의 호출 규칙을 struct 모르기 때문에 반환 형식의 get_c2 호출 규칙 struct 도 C++로 간주됩니다.

struct 뒤에 .를 반환하는 다른 함수 선언이 옵니다struct. 이 시점에서 컴파일러는 '의 호출 규칙이 C++임을 struct알고 있습니다. 마찬가지로, 함수 포인터는 struct정의 후에 struct 정의됩니다. 이제 struct 컴파일러는 C++ 호출 규칙을 사용합니다.

호환되지 않는 호출 규칙으로 인한 C2440 오류를 해결하려면 UDT 정의 후에 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
}

내부 포인터에 0 할당

내부 포인터에 0을 할당하는 경우에도 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이 있는 배열의 인스턴스를 만들려는 경우에도 발생할 수 있습니다. 자세한 내용은 배열을 참조하세요. 다음 샘플에서는 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++ 컴파일러에서는 소스 코드를 /clr컴파일할 때 연산자가 더 이상 캐스팅을 중지할 수const_cast 없습니다.

이 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 동작에 의존했던 코드가 손상되었습니다. 이 문제를 해결하려면 템플릿 매개 변수 형식과 일치하도록 템플릿 인수를 변경하거나 또는 C 스타일 캐스트를 reinterpret_cast 사용합니다.

이 샘플에서는 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);
}

이 오류는 에 정의된 매크로를 SINK_ENTRY_INFO 사용하는 ATL 코드에 나타날 수 있습니다 <atlcom.h>.

Copy-list-initialization

Visual Studio 2017 이상에서는 이니셜라이저 목록을 사용하여 개체 만들기와 관련된 컴파일러 오류가 올바르게 발생합니다. 이러한 오류는 2015년 Visual Studio catch되지 않았으며 충돌 또는 정의되지 않은 런타임 동작으로 이어질 수 있습니다. C++17 copy-list-initialization에서 컴파일러는 명시적 construct또는 오버로드 확인을 고려해야 하지만 오버로드가 실제로 선택된 경우 오류를 발생시켜야 합니다.

다음 예제는 2015 Visual Studio 컴파일되지만 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 };
}

클래스 construct이온의 cv 한정자

2015년 Visual Studio 컴파일러는 클래스 개체construct를 생성하거나 호출할 때 cv 한정자를 잘못 무시하는 경우가 있습니다. 이 결함으로 인해 크래시 또는 예기치 않은 런타임 동작이 발생할 수 있습니다. 다음 예제는 Visual Studio 2015에서 컴파일되지만 Visual Studio 2017 이상에서 컴파일러 오류가 발생합니다.

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

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

오류를 수정하려면 연산자 int()를 .로 const선언합니다.