【发布时间】:2019-09-13 13:57:10
【问题描述】:
以下代码:
int i = 1;
const int i_c = 2;
volatile int i_v = 3;
const volatile int i_cv = 4;
typedef std::variant<int, const int, volatile int, const volatile int> TVariant;
TVariant var (i );
TVariant var_c (i_c );
TVariant var_v (i_v );
TVariant var_cv(i_cv);
std::cerr << std::boolalpha;
std::cerr << std::holds_alternative< int>(var ) << std::endl;
std::cerr << std::holds_alternative<const int>(var_c ) << std::endl;
std::cerr << std::holds_alternative< volatile int>(var_v ) << std::endl;
std::cerr << std::holds_alternative<const volatile int>(var_cv) << std::endl;
std::cerr << var .index() << std::endl;
std::cerr << var_c .index() << std::endl;
std::cerr << var_v .index() << std::endl;
std::cerr << var_cv.index() << std::endl;
输出:
true
false
false
false
0
0
0
0
所以std::variant 转换构造函数不考虑转换源类型的 const volatile 限定符。这是预期的行为吗?
关于从cppreference.com转换构造函数的信息
如果对来自 Types 的每个 T_i 存在虚函数 F(T_i) 的重载,则构造一个包含替代类型 T_j 的变体,该替代类型 T_j 将由表达式
F(std::forward<T>(t))的重载决策选择...
问题在于,在上述情况下,这种假想函数的重载集是模棱两可的:
void F( int) {}
void F(const int) {}
void F( volatile int) {}
void F(const volatile int) {}
cppreference.com 对此案只字未提。标准有规定吗?
我正在自己实现std::variant 类。我的转换构造函数的实现基于this idea。结果与上面所示的相同(选择了第一个合适的替代方案,即使还有其他替代方案)。 libstdc++ 可能以相同的方式实现它,因为它也选择了第一个合适的替代方案。但我仍然想知道这是否是正确的行为。
【问题讨论】:
-
请注意
auto a = var_c将丢弃const,auto b = var_v将丢弃volatile,这是您的问题的根源。int在调用构造函数时总是自动推导出来的。 -
@MarekR 自动推断在哪里?变体的构造函数使用转发引用,其中
const和volatile限定符保留在模板参数IIRC (live demo) 中。我相信问题在于那些通过价值传递的imaginaryFUNfunctions。
标签: c++ variant c++-standard-library