为什么将int分配给std::variant<longint,…>失败?
在分配给变体时,我觉得我遗漏了一些关于 int 类型提升的明显信息。
在 gcc 9.3.0 版本(Ubuntu 9.3.0-11ubuntu0~18.04.1)上,使用 -std=c++17 编译,以下代码编译失败:
#include <variant>
#include <iostream>
int main()
{
std::variant<long int, bool> v; // works fine if "long" is omitted
long int sanity = 1; // verify that we can assign 1 to a long int; works fine
std::cout << sizeof(sanity) << "n";
v = 1; // compiler error here: why doesn't this assign to the long int variant of v?
return 0;
}
错误信息:
error: no match for ‘operator=’ (operand types are ‘std::variant<long int, bool>’ and ‘int’)
使这项工作按预期工作是否有什么神奇之处,而无需在作业中进行显式转换?谢谢!
回答
分配给变体不仅仅是分配给变体中当前活动的类型。相反,右手边的类型用于确定哪种可能的类型(替代项)与右手边的最佳匹配。然后,将该类型分配给。
因此,v = 1;不会自动分配给long int那已经是内在价值v,而是,编译时间计算完成,以确定是否long int或者bool是更好的匹配int(右手边的类型)。最佳匹配是使用重载解析规则确定的。换句话说,我们必须想象存在两个函数
void f(long int);
void f(bool);
并问问自己哪个函数会被调用f(1)。如果long int选择了重载,则v = 1分配给long int对象。如果bool选择了重载,则long int当前在里面的v被销毁,并bool构造一个值为 1的新对象。
不幸的是,这种重载决议是模棱两可的:1需要“积分转换”来匹配long int或bool。因此,给 1 赋值v是一个编译时错误。如果备选方案是int和bool,那么int备选方案将产生完全匹配并且不会有歧义。
这个特定的例子在 C++20 中是固定的:bool替代方案被排除在考虑之外,因为bool从一个int值初始化一个值需要一个缩小转换。因此,在 C++20 中,此代码将始终分配给long int替代项(如果bool当前在变体中存在对象,则将其销毁)。
THE END
二维码