Свертывание пересылочных ссылок - PullRequest
2 голосов
/ 22 февраля 2020

С учетом кода

struct S{};

template <typename T>
auto foo(T&& t)
{
    static_assert(std::is_same_v<T, std::remove_cvref_t<T>>);
}

void test()
{
    const S s;
    foo(s);  // error

    foo(S{});

    S s2;
    foo(s2); // error
}

T будет выводиться как

  1. S const&
  2. S
  3. S&

Почему T не выводится как

  1. S const
  2. S
  3. S

Почему T сохраняет ссылку в случае lvalue, а не в случае rvalue?

детская площадка

Ответы [ 2 ]

3 голосов
/ 22 февраля 2020

Одна из особенностей пересылки ссылок заключается в том, что у вас никогда не бывает «просто значения».

Когда T выводится как S, это только потому, что функция фактически принимает S&& .

Когда вы передаете свои локальные переменные, дедукция типов распознает, что это l-значения, и связывает их с обычными ссылками. A const один в случае const S s. Сигнатура функции «изменяется», чтобы отразить это.

У вас будет (const S&)&&, который, согласно стандарту, сворачивается до const S&, а затем у вас будет (S&)&&, который сворачивается до S&, согласно правилам свертывания ссылок.

См. [dcl.ref]

Убедитесь сами (Живая демоверсия)

2 голосов
/ 22 февраля 2020

Вот как ссылка для пересылки работает в вычет аргумента шаблона :

(выделено мной)

4) Если P является rvalue ссылка на cv-неквалифицированный параметр шаблона (так называемая ссылка на пересылку ), а соответствующий аргумент вызова функции - lvalue, ссылка на тип lvalue для A используется вместо A для вывода (Примечание: это основа для действия std::forward

Это означает, что если передано lvalue, T будет выведено как lvalue-reference. В противном случае, если T будет выводиться как один и тот же тип как для lvalue, так и для rvalue в ссылке на переадресацию, std::forward не может использоваться для повторного выполнения идеальной пересылки, то есть пересылка как lvalue при передаче lvalue и пересылка как rvalue, когда передается rvalue.

...