删除特殊成员的自定义类型的std::variant赋值运算符哪个编译器正确?
编译器行为差异判定结论
应当信任GCC和Clang的处理结果,MSVC此处的实现不符合C++标准要求。
问题复现
测试代码如下:
#include <variant> struct A { A() = default; A(A&&) = delete; }; struct B { B() = delete; B(A&&) {}; }; int main() { std::variant<A, B> v{}; v = A{}; }
原因说明
- 调用
v = A{}时,重载决议会匹配std::variant的模板赋值运算符template<class T> variant& operator=(T&&),首先会确定可选类型中匹配的目标类型:由于当前variant默认初始化后持有A类型实例,且A支持从右值A构造,因此选中目标类型为A,不会触发到B的类型转换。 - 该赋值运算符的实现要求,当目标类型的赋值操作无法保证不抛出异常时,需要采用「先构造临时对象、再移动构造到variant存储」的强异常安全实现逻辑,而
A的移动构造函数已经被显式删除,无法完成移动操作,因此该赋值运算符是不可用的,代码理应编译失败。 - MSVC的实现未正确检查移动构造函数的可用性,属于不符合C++标准的实现缺陷。
内容的提问来源于stack exchange,提问作者康桓瑋
相关产品推荐
相关产品推荐

