Share via


コンパイラ エラー 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 または型 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 *'
}

互換性のない呼び出し規則

次の例の 15 行目と 16 行目の C2440 エラーには、"Incompatible calling conventions for UDT return value (UDT 戻り値の呼び出し規約に互換性がありません)" というメッセージが表示されます。 UDT とは、クラス、struct、共用体などのユーザー定義型です。 このような種類の非互換性エラーが発生するのは、事前宣言の戻り値の型で指定された UDT の呼び出し規約が UDT の実際の呼び出し規約と競合する場合や、関数ポインターが関連する場合です。

この例では、最初に struct と struct を返す関数の事前宣言があります。 コンパイラでは、struct が C++ 呼び出し規則を使用すると仮定します。 次に、struct の定義があります。既定では、この定義は C 呼び出し規則を使用します。 コンパイラでは、struct 全体の読み込みが完了するまでは、その struct の呼び出し規則がわからないため、get_c2 の戻り値の型での struct の呼び出し規則も C++ であると仮定します。

struct の後に、struct を返す別の関数宣言が続きます。 この時点で、コンパイラでは、struct の呼び出し規則が C++ であることを認識しています。 同様に、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 を内部ポインターに割り当てる

C2440 は、内部ポインターに 0 を割り当てた場合にも発生することがあります。

// 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 は、型が Array である C++/CLI 配列のインスタンスを作成しようとした場合にも発生することがあります。 詳細については、「配列」を参照してください。 次の例では 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 Update 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);
}

このエラーは、<atlcom.h> で定義されている SINK_ENTRY_INFO マクロを使用する ATL コードに表示される場合があります。

Copy-list-initialization

Visual Studio 2017 以降では、初期化子リストを使用したオブジェクトの作成に関連するコンパイラ エラーが正しく発生します。 これらのエラーは、Visual Studio 2015 ではキャッチされなかったため、クラッシュまたは未定義の実行時の動作を引き起こす可能性がありました。 C++17 の copy-list-initialization で、コンパイラは、オーバーロードの解決のために明示的な construct を考慮する必要がありますが、そのオーバーロードが実際に選択された場合にエラーを発生させる必要があります。

次の例は、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-クラス construct の修飾子

Visual Studio 2015 では、construct を呼び出してクラス オブジェクトを生成するときに、コンパイラが誤って cv 修飾子を無視することがあります。 この欠陥により、クラッシュまたは予期しない実行時動作が発生する可能性があります。 次の例は、Visual Studio 2015 ではコンパイルされますが、Visual Studio 2017 以降ではコンパイラ エラーが発生します。

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

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

エラーを解決するには、operator int() を const として宣言します。