康桓瑋*_*康桓瑋 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)
我应该信任哪个编译器?
编辑
最初,没有language-lawyer标签,这就是我使用cppreference进行分析的原因。然而,查看最新的草案(相关部分),我没有看到任何会使其无效的内容。
我认为 MSVC 是不正确的。根据文档:
- 转换作业。
如果作用域内的每个函数同时存在虚函数重载,则确定
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 。
| 归档时间: |
|
| 查看次数: |
122 次 |
| 最近记录: |