編譯器錯誤 C2440
'initializing' : 無法從 'type1' 轉換為 'type2'
'conversion' : 無法從 'type1' 轉換為 'type2'
編譯程式無法隱含地從 *type1*
轉換為 *type2*
,或無法使用指定的轉換或轉換運算元。
備註
編譯程式會在無法從某個型別轉換為另一種類型時,隱含地或使用指定的轉換運算符來產生 C2440。 有許多方法可以產生此錯誤。 我們已在一節中列出一些常見的範例。
範例
字串常值C++為 const
如果您在設定編譯程式一致性選項/Zc:strictStrings
時,嘗試在 C++程式代碼中使用字串常值來初始化非constchar*
(或 wchar_t*
) ,可能會造成 C2440。 在 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 的實際呼叫慣例衝突,以及涉及函式指標時,就會造成這類不相容錯誤。
在此範例中,首先會針對 struct 傳回 struct的函式,有和的正向宣告。 編譯程序假設 struct 會使用 C++呼叫慣例。 接下來是 struct 定義,預設會使用 C 呼叫慣例。 由於編譯程式在完成讀取整個struct之前,並不知道的呼叫慣例,所以 在的傳回型get_c2
別中,的呼叫慣例structstruct也會假設為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
}
將零指派給內部指標
如果您將零指派給內部指標,也可能會發生 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
創造
如果您嘗試在類型為 Array的 C++/CLI 中建立數位的實例,也可能會發生 C2440。 如需詳細資訊,請參閱陣列。 下一個範例會產生 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") ];
元件延伸向下轉換
當您在下/clr
編譯原始程式碼時,Microsoft C++編譯程式不再允許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);
}
此錯誤可能會出現在 ATL 程式代碼 SINK_ENTRY_INFO
中使用 中所 <atlcom.h>
定義的巨集。
Copy-list-initialization
Visual Studio 2017 和更新版本會使用初始化運算式清單正確引發與物件建立相關的編譯程序錯誤。 這些錯誤未在 Visual Studio 2015 中攔截,並可能導致當機或未定義的運行時間行為。 在 C++17 複製清單初始化中,編譯程式必須考慮明確建構函式以進行多載解析,但如果實際選擇該多載,就必須引發錯誤。
下列範例會在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
若要更正錯誤,請將 operator int() 宣告為 const。