2012-03-17 4 views
14

Этот вопрос исходит из вопросов, поднятых this answer.Рамификация операторов присваивания со значениями вместо ссылок

Обычно мы определяем операторы присваивания копий для типа T как T& operator=(const T&) и переместите операторы присваивания для типа T как T& operator=(T&&).

Однако, что происходит, когда мы используем параметр значения, а не ссылку?

class T 
{ 
public: 
    T& operator=(T t); 
}; 

Это должно сделать T копией и переносом назначаемых. Однако, что я хочу знать, каковы языковые последствия для T?

В частности:

  1. ли это число в качестве оператора присваивания для копирования T, в соответствии со спецификацией?
  2. Учитывается ли это как оператор назначения перемещения для T, в соответствии со спецификацией?
  3. У команды T есть оператор копирования экземпляра?
  4. У команды T есть оператор присваивания оператора?
  5. Как это влияет на классы признаков, такие как std::is_move_assignable?
+0

Связанное обсуждение: http://cpp-next.com/archive/2009/08/want-speed-pass-by-value – mavam

+0

Я получаю ошибки компилятора на Visual Studio и g ++, если у меня есть что-то как T & operator = (T t) и T & operator = (T && t), поскольку он неоднозначен – user929404

+0

@ user929404: И вы должны. Дело в том, что вы заменяете * оба * копирование и перемещение присваиванием только с присвоением значения. –

ответ

14

Большинство из них описано в разделе 12.8. Пункт 17 определяет, что считается пользователем объявлены операторами присваивания копии:

Пользователем объявленного оператором копирующего присваивания X::operator= не является статической функцией, не являющегося члена шаблона класса X только с одним параметром типа X, X&, const X&, volatile X&, или const volatile X&.

Пункт 19 определяет, что считается пользователем объявлены операторами присваивания хода:

Пользователем объявленной оператор присваивания шага X::operator= не является статической функцией члена не-шаблона класса X с ровно один параметр тип X&&, const X&&, volatile X&&, или const volatile X&&.

Таким образом, он считается оператором присваивания копий, но не как оператором присваивания переадресации.

Пункт 18 говорит, когда компилятор генерирует операторы присваивания копирования:

Если определение класса не явно объявлять копию назначение оператора, один объявлен неявно. Если определение класса объявляет конструктор перемещения или оператор переадресации перемещения, неявный объявленный оператор назначения копирования определяется как удаленный; в противном случае он определяется как дефолт (8.4).Последний случай устарел, если класс имеет объявленный пользователем конструктор копирования или объявленный пользователем дескриптор .

Пункт 20 говорит нам, когда компилятор генерирует движение операторов присваивания:

Если определение класса X не явно объявить оператор присваивания шаг , один будет неявно объявлен дефолт, если и только если
[...]
- X не имеет пользовательскую объявленную оператор присваивания копии,
[...]

Поскольку у класса есть пользовательский оператор присваивания копии, ни один из неявных не будет сгенерирован компилятором.

std::is_copy_assignable и std::is_move_assignable описаны в таблице 49 как имеющее то же значение, соответственно is_assignable<T&,T const&>::value и is_assignable<T&,T&&>::value. Эта таблица говорит нам, что это is_assignable<T,U>::valuetrue, когда:

Выражение declval<T>() = declval<U>() хорошо образован при обработке в качестве невычисленного операнда (пункт 5). Проверка доступа выполняется как , если в контексте, не связанным с T и U. Рассматривается только актуальность непосредственного контекста выражения присваивания .

Так как declval<T&>() = declval<T const&>() и declval<T&>() = declval<T&&>() хорошо сформированный для этого класса, он по-прежнему считается копией назначаемой и двигаться переуступкой.

Как я уже упоминал в комментариях, все, что любопытно, заключается в том, что при наличии конструктора перемещения operator= будет правильно выполнять ходы, но технически не считать оператором присваивания перемещения. Еще страннее, если класс не имеет конструктора копирования: у него будет оператор присваивания копии, который не делает копии, а только движется.