std::variant 在 MSVC 和 gcc 中的行为不同

方圆圆*_*方圆圆 13 c++ std-variant

MSVC 19.28 拒绝以下代码,但 gcc 10.2 接受并输出 true false

#include <iostream>
#include <variant>

int main()
{
    std::variant<long long, double> v{ 0 };
    std::cout << std::boolalpha << std::holds_alternative<long long>(v) << ' ' << std::holds_alternative<double>(v) << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

根据cppreference

  1. 转换构造函数。如果同时对作用域中的每个from存在虚函数的重载,则构造一个包含替代类型的变体,该变体T_j将通过重载决议为表达式选择,除了:仅当声明对某些人有效时才考虑重载发明变量;直接初始化包含的值,就像通过从 直接非列表初始化一样。F(std::forward<T>(t))F(T_i)T_iTypes...F(T_i)T_i x[] = { std::forward<T>(t) };xstd::forward<T>(t)

和这个问题被转换成的哪个功能F(long long)F(double)选择agianst参数1由超负荷的分辨率。

转换intlong long整数转换(假设sizeof(long long)大于sizeof(int)),转换intdouble浮点整数转换,两者的排名都不高于另一个。所以调用是模棱两可的,程序格式不正确。

MSVC 确实像我预期的那样拒绝了代码,但令我惊讶的是,gcc 接受了它。此外,在cppreference上也有一个类似的例子:

std::variant<std::string> v("abc"); // OK
std::variant<std::string, std::string> w("abc"); // ill-formed
std::variant<std::string, const char*> x("abc"); // OK, chooses const char*
std::variant<std::string, bool> y("abc"); // OK, chooses string; bool is not a candidate
/* THIS ONE -> */ std::variant<float, long, double> z = 0; // OK, holds long
                                         // float and double are not candidates 
Run Code Online (Sandbox Code Playgroud)

所以我的问题是:是 gcc 还是 MSVC 不符合,还是我的理解有误?

Dav*_*ing 5

在引用的规则中,仅当候选类型的复制列表初始化从参数类型起作用时才考虑重载。此检查不会\xe2\x80\x99t(can\xe2\x80\x99t)考虑参数的常量表达式状态,因此int对于任何浮点类型都是缩小转换,并且列表初始化不允许(尽管事实上在典型的实现中double可以准确地表示int) 的每个值。因此, GCC(libstdc++)忽略替代方案是正确的double

\n