Зачем использовать идентификатор в прямом определении для ссылки на С++ 0x rvalue?

В Краткое введение в Rvalue References, forward определяется следующим образом:

  template <typename T>
  struct identity { typedef T type; };

  template <typename T>
  T &&forward(typename identity<T>::type &&a) { return a; }

Какую цель выполняет класс identity? Почему бы и нет:

  template <typename T>
  T &&forward(T &&a) { return a; }

Ответы

Ответ 1

Цель identity заключалась в том, чтобы сделать T невыводимым. То есть, чтобы заставить клиента явно отправлять T при вызове forward.

forward(a);     // compile-time error
forward<A>(a);  // ok

Причина, по которой это необходимо, заключается в том, что параметр шаблона является коммутатором, с которым клиент сообщает компилятору передать аргумент как значение lvalue, либо как rvalue. Если вы случайно забыли предоставить эту информацию, тогда lvalues ​​всегда возвращаются как lvalues ​​и rvalues ​​всегда возвращаются как rvalues. Хотя сначала это может звучать так, как вы хотите, это действительно не так.

template <class T, class A1>
std::shared_ptr<T>
factory(A1&& a1)
{
    return std::shared_ptr<T>(new T(std::forward<A1>(a1)));
}

В приведенном выше примере a1 всегда является lvalue. Но "переключатель" a1 может быть или не быть ссылкой lvalue. Если это ссылка lvalue, a1 возвращается как lvalue, в противном случае a1 возвращается как rvalue. Если автор factory случайно забыл поставить A1, использование identity напоминает его во время компиляции.

Примечание. В окончательном проекте отсутствует identity, но используется с тем же назначением remove_reference для этой же цели.