I have a std::variant of different types including int32_t, int64_t, float, double, std::string and bool.
When I assign a string literal (const char*, which is not present in this variant), I assumed it will be implicitly converted to std::string and it worked as I expected with MinGW (9.0.0 64-bit). But with MSVC (2019 64-bit) it implicitly converted to bool.
If I explicitly converts it to std::string and then assign it to variant it works fine with both compilers.
Here's the code
#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;
}
Here's the output
With MinGW 9.0.0
Build With Compiler Set [ MSVC ]
index = 5
[exception = bad variant access]
With MSVC 2019
Build With Compiler Set [ MinGW ]
index = 4
[string = ABCDE]
Index 4 denotes to KString (aka std::string) and 5 denotes to KBoolean (aka bool).
So my question is why both compilers are giving different results?
CodePudding user response:
The behavior of variant changed for this exact case in C 20. See What is the best way to disable implicit conversion from pointer types to bool when constructing an std::variant? for a longer discussion.
CodePudding user response:
Looks like bug in standard library which has been fixed.
I've wrote this test:
#include "catch2/catch_all.hpp"
#include <variant>
TEST_CASE("std::variant literal conversion") {
std::variant<int, double, std::string, bool> var;
CHECK(var.index() == 0);
var = 1;
CHECK(var.index() == 0);
CHECK(std::holds_alternative<int>(var));
var = 1.0;
CHECK(var.index() == 1);
CHECK(std::holds_alternative<double>(var));
var = std::string{"foo"};
CHECK(var.index() == 2);
CHECK(std::holds_alternative<std::string>(var));
var = true;
CHECK(var.index() == 3);
CHECK(std::holds_alternative<bool>(var));
var = "foo";
CHECK(var.index() == 2);
CHECK(std::holds_alternative<std::string>(var));
}
And it fails on GCC 9.4 and Clang 10.0.1 and it is fine on GCC 10.1 and Clang 11.0.
