mingw vs msvc关于字符串文字的隐式转换

mingw vs msvc on implicit conversion of string literals

我有一个 std::variant 不同类型,包括 int32_tint64_tfloatdoublestd::stringbool. 当我分配一个字符串文字(const char*,此变体中不存在)时,我假设它将隐式转换为 std::string,并且它按我预期的方式工作 MinGW (9.0.0 64-bit)。但是使用 MSVC (2019 64-bit) 它隐式转换为 bool。 如果我明确地将它转换为 std::string 然后将它分配给 variant 它在两个编译器上都可以正常工作。

这是代码

#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;
}

这是输出
使用 MinGW 9.0.0

     Build With Compiler Set [ MSVC ]
     index = 5
          [exception = bad variant access]

使用 MSVC 2019

Build With Compiler Set [ MinGW ]
index = 4
    [string = ABCDE]

索引 4 表示 KString(又名 std::string),索引 5 表示 KBoolean(又名 bool)。
所以我的问题是为什么两个编译器给出不同的结果?

在 C++20 中,对于这种情况,变体的行为发生了变化。 有关更长时间的讨论,请参阅

看起来像是标准库中的错误,已修复。

我写过这个测试:

#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));
}

它在 GCC 9.4 和 Clang 10.0.1 上失败,在 GCC 10.1 和 Clang 11.0 上没问题。

Live demo