具有已删除特殊成员函数的自定义类型 std::variant 的赋值运算符?

康桓瑋*_*康桓瑋 5 c++ assignment-operator language-lawyer c++20 std-variant

考虑:

#include <variant>

struct A { 
  A() = default;
  A(A&&) = delete;
};

struct B { 
  B() = delete;
  B(A&&) {};
};

int main() {
  std::variant<A, B> v{};
  v = A{};
}
Run Code Online (Sandbox Code Playgroud)

MSVC 接受了它,而 GCC 和 Clang 以相同的错误消息拒绝了它

opt/compiler-explorer/gcc-snapshot/lib/gcc/x86_64-linux-gnu/12.0.0/../../../../include/c++/12.0.0/variant:1465:3: error: call to deleted member function 'operator='
                operator=(variant(std::forward<_Tp>(__rhs)));
                ^~~~~~~~~
<source>:15:5: note: in instantiation of function template specialization 'std::variant<A, B>::operator=<A>' requested here
  v = A{};
    ^
Run Code Online (Sandbox Code Playgroud)

我应该信任哪个编译器?

Dan*_*ica 3

编辑

最初,没有language-lawyer标签,这就是我使用cppreference进行分析的原因。然而,查看最新的草案(相关部分),我没有看到任何会使其无效的内容。


我认为 MSVC 是不正确的。根据文档

  1. 转换作业。
  • 如果作用域内的每个函数同时存在虚函数重载,则确定T_j重载决策将为表达式选择的替代类型,但以下情况除外:F(std::forward<T>(t))F(T_i)T_iTypes...

    • F(T_i) 仅当声明T_i x[] = { std::forward<T>(t) };对于某些发明变量有效时才考虑重载x

对于某些具有转发引用参数并使用A{}参数调用它的虚构函数,A x[] = { std::forward<T>(t) };在有效时无效B x[] = { std::forward<T>(t) };。因此,T_j应解决为B。现场演示: https: //godbolt.org/z/fM67e7oGj

然后:

  • 如果*this已经持有T_j...

这不适用,因为v不包含B.

下一个:

  • 否则,如果std::is_nothrow_constructible_v<T_j, T> || !std::is_nothrow_move_constructible_v<T_j>true...

这也不适用,因为这个表达式是false; 现场演示: https: //godbolt.org/z/x674rnbcj(并且 MSVC 同意这一点: https: //godbolt.org/z/5Techn8jG)。

最后:

  • 否则,相当于this->operator=(variant(std::forward<T>(t))).

但是,此调用无法使用 MSVC 进行编译:https ://godbolt.org/z/cWr4f6EhK 。