Update:这是一个 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;
}
根据参考参数 https://en.cppreference.com/w/cpp/utility/variant/variant:
- 转换构造函数。构造一个包含
另类类型
T_j
将由重载决议选择
表达方式F(std::forward<T>(t))
如果出现超载
虚函数F(T_i)
对于每一个T_i
from Types...
在范围内
同时,除了:
超载F(T_i)
仅当以下情况时才考虑
宣言T_i x[] = { std::forward<T>(t) };
对某些人有效
发明变量x
;
直接初始化包含的值,就像通过直接非列表初始化一样std::forward<T>(t)
.
并且问题被转换为哪个函数F(long long)
and F(double)
是根据参数选择的1
通过重载决议。
转换int
to long long
是一个积分转换(假设sizeof(long long)
大于sizeof(int)
)并转换int
to double
是浮点积分转换,两者的排名都不高。所以调用是不明确的并且程序是不正确的。
正如我所料,MSVC 确实拒绝了该代码,但令我惊讶的是,gcc 接受了它。除此之外,网上还有一个类似的例子参考参数 https://en.cppreference.com/w/cpp/utility/variant/variant:
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不符合要求,还是我的理解错误?