更新: 这是C++标准的缺陷,在C++20 (P0608R3)中已得到修复。此外,VS 2019 16.10通过使用/std:c++20
修复了这个错误。
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;
}
根据cppreference:
转换构造函数。构造一个变量,其中包含选择类型
T_j
的替代方案,该类型将为表达式F(std::forward<T>(t))
选择重载分辨率,如果在同一时间范围内作用域中存在每个T_i
的虚构函数F(T_i)
的重载,则仅考虑重载F(T_i)
,除非对于某些虚构变量x
,声明T_i x[] = { std::forward<T>(t) };
有效;以直接非列表初始化方式初始化所包含的值,如同通过std::forward<T>(t)
进行直接非列表初始化。问题是将
int
转换为long long
是整数转换(假设sizeof(long long)
大于sizeof(int)
),将int
转换为double
是浮点整数转换,两者都不高于另一个。 因此,调用是模棱两可的,程序是有缺陷的。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
所以我的问题是:gcc或MSVC不符合标准,还是我的理解有误?