Partilhar via


Erro do compilador C2440

'inicializando' : não é possível converter de 'type1' para 'type2'
'conversão' : não é possível converter de 'tipo1' para 'tipo2'

Observações

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.

O compilador gera C2440 quando não pode converter de um tipo para outro, implicitamente ou usando o cast especificado ou operador de conversão. Há muitas maneiras de gerar esse erro. Listamos alguns comuns na seção Exemplos.

Exemplos

Os literais de cadeia de caracteres C++ são const

C2440 pode 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 é definida. Em C, o tipo de uma cadeia de caracteres literal é um array de char, mas em C++, é um array de const char. Este exemplo gera 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
}

Os literais C++20 u8 são const char8_t

Em C++20 ou sob /Zc:char8_t, um caractere literal UTF-8 ou cadeia de caracteres (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 C++17 e 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

Poderá ver C2440 se tentar converter um ponteiro para membro em 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);
   }
};

Elenco de tipo indefinido

O compilador emite C2440 se você tentar converter a partir de um tipo que é apenas declarado para frente, mas não definido. Este exemplo gera 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 pela mensagem Incompatible calling conventions for UDT return value. Um UDT é um tipo definido pelo usuário, como uma classe, structou 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, há primeiro declarações antecipadas para um struct e para uma função que retorna o struct. O compilador assume que o struct usa a convenção de chamada C++. Em seguida, está a struct definição, que usa a convenção de chamada C por padrão. Como o compilador não conhece a convenção de chamada de struct até terminar de ler o struct completo, a convenção de chamada para o struct no tipo de retorno de get_c2 também é assumida como C++.

O struct é seguido por outra declaração de função que retorna o struct. Neste ponto, o compilador reconhece 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 struct definição. 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 do 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

C2440 também pode ocorrer se 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

C2440 também pode ocorrer para 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 User-Defined conversões (C++/CLI)). Este exemplo gera 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 Criação

C2440 também pode ocorrer ao tentar criar uma instância de uma matriz em C++/CLI cujo tipo é um Array. Para obter mais informações, consulte 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

C2440 também pode ocorrer devido a alterações no recurso de atributos. O exemplo a seguir gera C2440.

// c2440f.cpp
// compile with: /LD
[ module(name="PropDemoLib", version=1.0) ];   // C2440
// try the following line instead
// [ module(name="PropDemoLib", version="1.0") ];

Extensões de componentes para baixo moldes

O compilador Microsoft C++ não permite mais que o const_cast operador faça downcast quando se compila código-fonte em /clr.

Para resolver este C2440, use o operador de molde correto. Para obter mais informações, consulte Operadores de transmissão.

Este exemplo gera 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 na correspondência ao modelo de conformidade

C2440 pode ocorrer devido a alterações de conformidade no compilador do Visual Studio 2015 Update 3. Anteriormente, o compilador tratava incorretamente certas expressões distintas como o mesmo tipo ao identificar uma correspondência de modelo para uma static_cast operação. Agora, o compilador distingue os tipos corretamente, e o código que dependia do comportamento anterior static_cast é quebrado. Para corrigir este problema, altere o argumento do template para corresponder ao tipo de parâmetro do template ou use um casting ao estilo C.

Este exemplo gera 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);
}

Este erro pode aparecer no código ATL que usa a SINK_ENTRY_INFO macro definida em <atlcom.h>.

Inicialização da lista de cópia

O Visual Studio 2017 e posterior geram corretamente erros de compilador relacionados à criação de objetos usando listas de inicializadores. Esses erros não foram detetados no Visual Studio 2015 e podem levar a falhas ou comportamento de tempo de execução indefinido. Em C++17 copy-list-initialization, o compilador é obrigado a 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 compila 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 classes

No Visual Studio 2015, o compilador às vezes ignora incorretamente o qualificador cv ao gerar um objeto de classe por meio de uma chamada de construtor. Esse defeito pode potencialmente causar uma falha ou um comportamento de tempo de execução inesperado. O exemplo a seguir compila no Visual Studio 2015, mas gera um erro de compilador no Visual Studio 2017 e posterior:

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

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

Para corrigir o erro, declare o operador int() como const.