2016-11-26 20 views
17

Различия между ссылками RValue и ссылками экспедиторской было сделано достаточно ясно, в этом примере Скотт Мейерс:Это ссылка для пересылки?

Widget&& var1 = someWidget;  // here, “&&” means rvalue reference (1) 

auto&& var2 = var1;    // here, “&&” does not mean rvalue reference (2) 

template<typename T> 
void f(std::vector<T>&& param); // here, “&&” means rvalue reference (3) 

template<typename T> 
void f(T&& param);    // here, “&&”does not mean rvalue reference (4) 

По существу различие происходит, когда мы имеем выводимые контекст, следовательно, случай (3) четко указано, что мы имеют vector<...>&&, тогда как T в случае (4) должен быть выведен и (после применения правил сворачивания ссылок), классифицированных в терминах «категория стоимости».

Но что происходит с более сложным сопоставлением шаблонов? Рассмотрим следующий случай, например:

template <template <class...> class Tuple, class... Ts> 
void f(Tuple<Ts...>&& arg) 
{ 

} 

Что && значит здесь?

+1

Выделенный контекст не имеет значения. (3) и (4) являются выводимыми. – Oktalist

ответ

14

В последнем примере arg является ссылкой на rvalue.

Ссылка пересылка является ссылкой на Rvalue к CV-неквалифицированным параметра шаблона

Tuple<Ts...> и не является параметром шаблона.

(Цитирование из [temp.deduct.call].)

9

Это является ссылкой Rvalue, а не ссылка переадресации.

Самый простой способ убедиться в том, чтобы попытаться передать именующее выражение, если это не удается, то это ссылка Rvalue, если нет, то ссылка переадресации:

template<typename... Ts> 
struct foo {}; 

//f function definition 

int main() { 
    foo<int, double> bar; 
    f(bar); // fails! Cannot bind lvalue to rvalue reference 
    f(foo<int, double>{}); // ok, rvalue is passed 
} 
1

Ссылка экспедиторская концепция не стандартная концепция, полезно признать ее, когда вы ее видите, но если вы хотите правильно ее понять и справиться с ней, вы должны понять эталонную арифметику.(Я считаю, что книга Мейера имеет также главу о нем)

Что скрывается за понятием ссылки переадресации является эталонным арифметика:

  • & & & & = & &
  • & & & = &
  • & & & = &
  • & & = &

Давайте моделировать шаблон компилятор типа вывод со ссылкой экспедиторской

template<class T> 
void foo(T&&); 
//... 
const int i=42; 
foo(i); // the compiler will defines T = const int & 
     //   T&& = const int & && = const int & 
     // => the compiler instantiates void foo<const int &>(const int &); 
foo(6*7);// the compiler will defines T = int 
     //   T&& = int && 
     // the compiler instantiates void foo<int>(int &&); 

в такой ситуации, конкретизацией шаблона обув может производит функцию который принимает аргумент с помощью ссылки lvalue или функций, которая принимает аргументы rvalue: ссылка на пересылку - либо ссылку rvalue или ссылку lvalue, в зависимости от вычета типа шаблона. Он назван так, потому что в такой ситуации, то параметр должен быть передан как Lvalue или как xvalue, и это работа T&& std::forward<T>(T&& a)

Если вы объявляете функция имеет:

template<class T> 
void foo(ATemplateClass<T> && a); 

независимо от типа, выведенного для T компилятором, вы получите ссылочный параметр rvalue.

+0

Вы уверены, что используете ваш образец? Я считаю, что foo (42) и foo (6 * 7) находятся в одной лодке здесь: https://godbolt.org/g/jOEK9b – RTempete

+0

@RTempete Эта часть сообщения кажется неправильной: как вы видели, оба вывести на 'int &&' - то же самое, а не 'const'. Если бы Олив объяснил, почему они думают, что это должно быть 'const', и/или должна быть какая-то разница в зависимости от того, будет ли задействовано (тривиальное, оптимизированное даже на' -O0') выражение, это будет намного больше полезно. –

+0

Извините, в коде примера были две ошибки. f (42) -> rvalue и f (6 * 7). – Oliv