C++ 赋值运算符与值而非引用的分支

C++ 赋值运算符与值而非引用的分支,c++,c++11,language-lawyer,move-semantics,C++,C++11,Language Lawyer,Move Semantics,这个问题来自于委员会提出的问题 通常,我们将类型T的复制赋值运算符定义为T&operator=(const T&),将类型T的赋值运算符定义为T&operator=(T&&) 但是,当我们使用值参数而不是引用时会发生什么 class T { public: T& operator=(T t); }; 这将使复制和移动都可分配。然而,我想知道的是T的语言分支是什么 具体而言: 根据规范,这是否算作T的复制分配运算符 根据规范,这是否算作T的移动分配运算符 T是否有编译器生成的复制赋值

这个问题来自于委员会提出的问题

通常,我们将类型
T
的复制赋值运算符定义为
T&operator=(const T&)
,将类型
T
的赋值运算符定义为
T&operator=(T&&)

但是,当我们使用值参数而不是引用时会发生什么

class T
{
public:
  T& operator=(T t);
};
这将使复制和移动都可分配。然而,我想知道的是
T
的语言分支是什么

具体而言:

  • 根据规范,这是否算作
    T
    的复制分配运算符
  • 根据规范,这是否算作
    T
    的移动分配运算符
  • T
    是否有编译器生成的复制赋值运算符
  • T
    是否有编译器生成的移动赋值运算符
  • 这会如何影响traits类,比如
    std::ismove\u assignable

  • 其中大部分内容见§12.8。第17段定义了什么算作用户声明的复制分配运算符:

    用户声明的复制赋值运算符
    X::operator=
    是类
    X
    的非静态非模板成员函数,只有一个类型为
    X
    X&
    常量X&
    volatile X&
    常量volatile X&
    的参数

    第19段定义了用户声明的移动分配运算符:

    用户声明的移动分配运算符
    X::operator=
    是非静态的 类
    X
    的非模板成员函数,只有一个参数 键入
    X&
    const X&
    volatile X&
    ,或
    const volatile X&

    因此,它算作复制分配运算符,但不算作移动分配运算符

    第18段说明编译器何时生成复制赋值运算符:

    如果类定义没有显式声明副本赋值 运算符,则隐式声明一个。如果类定义声明 移动构造函数或移动赋值运算符,隐式 已声明的副本分配运算符定义为已删除;否则, 定义为默认值(8.4)。如果 类具有用户声明的复制构造函数或用户声明的 析构函数

    第20段告诉我们编译器何时生成移动赋值运算符:

    如果类X的定义没有显式声明移动 赋值运算符,如果 只有当
    […]
    -X没有用户声明的复制分配运算符,
    [……]

    由于类有一个用户声明的复制赋值运算符,编译器不会生成任何一个隐式运算符

    std::is\u copy\u assignable
    std::is\u move\u assignable
    在表49中被描述为分别具有与
    is\u assignable::value
    is\u assignable::value
    相同的值。该表告诉我们,
    is_assignable::value
    is
    true
    当:

    表达式
    declval()=declval()
    在处理时格式良好 作为未赋值的操作数(第5条)。访问检查按以下步骤执行: 如果在与
    T
    U
    无关的上下文中。只有该文件的有效性 考虑赋值表达式的直接上下文

    由于该类的
    declval()=declval()
    declval()=declval()
    都是格式良好的,因此它仍然算作复制可分配和移动可分配


    正如我在评论中提到的,奇怪的是,在存在移动构造函数的情况下,
    operator=
    将正确地执行移动,但从技术上讲不算作移动赋值操作符。更奇怪的是,如果类没有复制构造函数:它将有一个复制赋值操作符,它不进行复制,只进行移动。

    相关讨论:如果我同时拥有t&operator=(t t)和t&operator=(t&&t),则Visual Studio和g++都会出现编译器错误ambiguous@user929404:你应该这样做。关键是要将复制和移动赋值都替换为仅值赋值。