[英]std::variant behaves differently in MSVC and gcc
MSVC 19.28 rejects the following code but gcc 10.2 accepts it and outputs true false
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;
}
According to cppreference :根据cppreference :
- Converting constructor.
转换构造函数。 Constructs a variant holding the alternative type
T_j
that would be selected by overload resolution for the expressionF(std::forward<T>(t))
if there was an overload of imaginary functionF(T_i)
for everyT_i
fromTypes...
in scope at the same time, except that: An overloadF(T_i)
is only considered if the declarationT_i x[] = { std::forward<T>(t) };
如果
Types...
中的每个T_i
存在假想 functionF(T_i)
的重载,则构造一个包含替代类型 T_j 的变体,该替代类型T_j
将由表达式F(std::forward<T>(t))
的重载决策选择。Types...
同时在 scope 中,除了: 仅当声明T_i x[] = { std::forward<T>(t) };
时才考虑重载F(T_i)
is valid for some invented variablex
;对某些发明的变量
x
有效; Direct-initializes the contained value as if by direct non-list-initialization fromstd::forward<T>(t)
.直接初始化包含的值,就像通过来自
std::forward<T>(t)
的直接非列表初始化一样。
And the question is converted to which function of F(long long)
and F(double)
is selected agianst argument 1
by overload resolution.问题被转换为通过重载决议选择
F(long long)
和F(double)
的 function 与参数1
中的哪个。
Converting int
to long long
is an integral conversion (supposing sizeof(long long)
is bigger than sizeof(int)
) and converting int
to double
is an floating-integral conversion, neither ranks higher that the other.将
int
转换为long long
是一个整数转换(假设sizeof(long long)
大于sizeof(int)
),将int
转换为double
是一个浮点整数转换,两者的排名都不高于另一个。 So the call is ambiguous and the program is ill-formed.所以调用是模棱两可的,程序格式不正确。
MSVC does rejected the code as I expected but to my surprise, gcc accepts it. MSVC 确实拒绝了该代码,但令我惊讶的是,gcc 接受了它。 Besides, there is also a similar example on cppreference :
此外,在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
So my question is: is gcc or MSVC non-conformance, or my understanding is wrong?所以我的问题是:是gcc还是MSVC不符合,还是我的理解有误?
In the quoted rule, an overload is considered only if copy-list-initialization for the candidate type works from the argument type.在引用的规则中,仅当候选类型的复制列表初始化从参数类型工作时才考虑重载。 This check doesn't (can't) consider the constant-expression status of the argument, so
int
to any floating-point type is a narrowing conversion and is disallowed by list-initialization (despite the fact that on typical implementations double
can exactly represent every value of int
).此检查不(不能)考虑参数的常量表达式状态,因此任何浮点类型的
int
都是缩小转换,并且列表初始化不允许(尽管在典型实现中double
可以完全表示int
的每个值)。 GCC ( ie , libstdc++) is therefore correct to disregard the double
alternative.因此,GCC(即libstdc++)忽略
double
选择是正确的。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.