Erro do compilador C2440
'inicializando' : não é possível converter de 'tipo1' para 'tipo2'
'conversão' : não é possível converter de 'tipo1' para 'tipo2'
O compilador não pode converter implicitamente de *type1*
para *type2*
, ou não pode usar o operador de conversão ou a conversão especificada.
Comentários
O compilador gera o erro C2440 quando não pode converter de um tipo para outro, seja implicitamente ou usando o operador de conversão ou a conversão especificada. Há muitas maneiras de gerar esse erro. Listamos alguns erros comuns na seção Exemplos.
Exemplos
Literais de cadeia de caracteres C++ são const
O erro C2440 poderá ser causado se você tentar inicializar um não constchar*
(ou wchar_t*
) usando um literal de cadeia de caracteres no código C++, quando a opção /Zc:strictStrings
de conformidade do compilador estiver definida. Em C, o tipo de literal de cadeia de caracteres é matriz de char
, mas em C++, é matriz de const char
. Este exemplo gera o erro 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
}
Literais u8
do C++20 são const char8_t
Em C++20 ou abaixo de /Zc:char8_t
, um caractere literal ou cadeia de caracteres literal UTF-8 (como u8'a'
ou u8"String"
) é do tipo const char8_t
ou const char8_t[N]
, respectivamente. Este exemplo mostra como o comportamento do compilador muda entre o C++17 e o 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
}
Ponteiro para membro
Você poderá ver o erro C2440 se tentar converter um ponteiro em membro para void*
. O próximo exemplo gera 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);
}
};
Conversão de tipo indefinido
O compilador emitirá o erro C2440 se você tentar converter de um tipo que é encaminhado apenas declarado, mas não definido. Este exemplo gera o erro 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 *'
}
Convenção de chamada incompatível
Os erros C2440 nas linhas 15 e 16 do próximo exemplo são qualificados com a mensagem Incompatible calling conventions for UDT return value
. Um UDT é um tipo definido pelo usuário, como uma classe, struct ou união. Esses tipos de erros de incompatibilidade são causados quando a convenção de chamada de um UDT especificado no tipo de retorno de uma declaração de encaminhamento entra em conflito com a convenção de chamada real do UDT e quando um ponteiro de função está envolvido.
No exemplo, primeiro há declarações de encaminhamento para um struct e para uma função que retorna o struct. O compilador pressupõe que o struct usa a convenção de chamada C++. Em seguida está a definição de struct, que usa a convenção de chamada C por padrão. Como o compilador não sabe a convenção de chamada do struct até concluir a leitura de todo o struct, a convenção de chamada para o struct no tipo de retorno do get_c2
também é considerada C++.
O struct é seguido por outra declaração de função que retorna o struct. Neste ponto, o compilador sabe que a convenção de chamada do struct é C++. Da mesma forma, o ponteiro da função, que retorna o struct, é definido após a definição de struct. O compilador agora sabe que struct usa a convenção de chamada C++.
Para resolver erros C2440 causados por convenções de chamada incompatíveis, declare funções que retornam um UDT após a definição de 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
}
Atribuir zero ao ponteiro interior
O erro C2440 também poderá ocorrer se você atribuir zero a um ponteiro interior:
// 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
}
Conversões Definidas pelo Usuário
O erro C2440 também pode ocorrer em um uso incorreto de uma conversão definida pelo usuário. Por exemplo, quando um operador de conversão foi definido como explicit
, o compilador não pode usá-lo em uma conversão implícita. Para obter mais informações sobre conversões definidas pelo usuário, consulte Conversões definidas pelo usuário (C++/CLI)). Este exemplo gera o erro 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);
}
Criação de System::Array
O erro C2440 também pode ocorrer se você tentar criar uma instância de uma matriz em C++/CLI cujo tipo é um Array. Saiba mais em Matrizes. O próximo exemplo gera 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));
}
Atributos
O erro C2440 também pode ocorrer devido a alterações no recurso de atributos. O exemplo a seguir gera o erro C2440.
// c2440f.cpp
// compile with: /LD
[ module(name="PropDemoLib", version=1.0) ]; // C2440
// try the following line instead
// [ module(name="PropDemoLib", version="1.0") ];
Conversões de redução de extensões de componente
O compilador do Microsoft C++ não permite mais que o operador const_cast
seja reduzido ao compilar o código-fonte em /clr
.
Para resolver esse erro C2440, use o operador de conversão correto. Saiba mais em Operadores de conversão.
Este exemplo gera o erro 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
}
Alterações de correspondência de modelo de conformidade
O erro C2440 pode ocorrer devido a alterações de conformidade no compilador no Visual Studio 2015 Atualização 3. Anteriormente, o compilador tratava incorretamente determinadas expressões distintas como o mesmo tipo ao identificar uma correspondência de modelo para uma operação static_cast
. Agora, o compilador distingue os tipos corretamente e o código que se baseava no comportamento static_cast
anterior está corrompido. Para corrigir esse problema, altere o argumento do modelo para corresponder ao tipo de parâmetro do modelo ou use uma conversão de estilo C ou reinterpret_cast
.
Este exemplo gera o erro 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);
}
Esse erro pode aparecer no código ATL que usa a macro SINK_ENTRY_INFO
definida em <atlcom.h>
.
Inicialização de lista de cópia
O Visual Studio 2017 e posteriores geram corretamente erros de compilador relacionados à criação de objetos usando listas de inicializadores. Esses erros não eram pegos no Visual Studio 2015 e podiam ocasionar falhas ou comportamento indefinido de runtime. Na inicialização da lista de cópias do C++17, o compilador deve considerar um construtor explícito para resolução de sobrecarga, mas deve gerar um erro se essa sobrecarga for realmente escolhida.
O exemplo a seguir é compilado no Visual Studio 2015, mas não no 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 &'
}
Para corrigir o erro, use a inicialização direta:
// C2440k.cpp
struct A
{
explicit A(int) {}
A(double) {}
};
int main()
{
const A& a2{ 1 };
}
Qualificadores CV na construção de classe
No Visual Studio 2015, às vezes, o compilador ignora incorretamente o qualificador CV ao gerar um objeto de classe por meio de uma chamada do construtor. Eventualmente, esse defeito pode gerar uma falha ou comportamento inesperado do runtime. O exemplo a seguir é compilado no Visual Studio 2015, mas gera um erro de compilador no Visual Studio 2017 e posteriores:
struct S
{
S(int);
operator int();
};
int i = (const S)0; // error C2440
Para corrigir o erro, declare o operador int() como const.