mingw vs msvc en la conversión implícita de literales de cadena
Tengo un std::variant
de diferentes tipos, incluyendo int32_t
, int64_t
, float
, double
, std::string
y bool
.
Cuando asigno un literal de cadena (const char *
, que no está presente en este variant), asumí que se convertiría implícitamente a std::string
y funcionó como esperaba con MinGW (9.0.0 de 64 bits). Pero con MSVC (2019 de 64 bits), se convirtió implícitamente a bool
.
Si lo convierto explícitamente a std::string
y luego lo asigno al variant, funciona bien con ambos compiladores.
Aquí está el código:
#include <iostream>
#include <variant>
#if defined(__MINGW64__) || defined(__MINGW32__)
#define CMP_NAME "[ MinGW ]"
#elif defined(_MSC_VER)
#define CMP_NAME "[ MSVC ]"
#else
#define CMP_NAME "[ Others ]"
#endif
using KInt32 = int32_t;
using KInt64 = int64_t;
using KFloat = float;
using KDouble = double;
using KString = std::string;
using KBoolean = bool;
using Variant = std::variant<
KInt32, /*0*/
KInt64, /*1*/
KFloat, /*2*/
KDouble, /*3*/
KString, /*4*/
KBoolean /*5*/
> ;
int main()
{
//passing a const char* to Variant [target is to initialize as KString]
Variant var = "ABCDE";
std::cout << "Build With Compiler Set " << CMP_NAME << std::endl;
std::cout << "index = " << var.index() << std::endl;
try {
KString &str = std::get<kstring>(var);
std::cout << "\t[string = " << str << "]" << std::endl;
}
catch (const std::exception &e) {
std::cout << "\t[exception = " << e.what() << "]" << std::endl;
}
return 0;
}
Aquí está la salida:
Con MinGW 9.0.0
Build With Compiler Set [ MSVC ]
index = 5
[exception = bad variant access]
Con MSVC 2019
Build With Compiler Set [ MinGW ]
index = 4
[string = ABCDE]
El índice 4 denota a KString
(también conocido como std::string
) y el 5 denota a KBoolean
(también conocido como bool
).
Entonces mi pregunta es ¿por qué ambos compiladores dan resultados diferentes?
davy.ai
La razón por la que ambos compiladores están dando resultados diferentes se debe a la implementación diferente de la clase
std::variant
en los dos compiladores.Según el estándar C++17, cuando se pasa un literal de cadena a un objeto
std::variant
que tiene un tipostd::string
como una de sus alternativas, el literal de cadena debe convertirse implícitamente enstd::string
. Sin embargo, el estándar no especifica qué debería suceder si se pasa un literal de cadena a un objetostd::variant
que no tienestd::string
como una de sus alternativas.Por ejemplo, en el caso de MSVC, parece que la implementación permite que el literal de cadena se convierta implícitamente en
bool
, que es la última alternativa en el objetoVariant
. Por otro lado, en el caso de MinGW, parece que la implementación intenta hacer coincidir el literal de cadena con la alternativastd::string
del objetoVariant
, como se esperaba.Por lo tanto, es importante siempre convertir explícitamente un literal de cadena en
std::string
antes de asignarlo a un objetostd::variant
para garantizar el comportamiento correcto en diferentes compiladores.