Почему мой код печатает rvalue 2 раза вместо rvalue & lvalue? - PullRequest
10 голосов
/ 21 июня 2019

Итак, я хотел попрактиковаться в использовании std::forward и создал класс Test с двумя конструкторами. 1 с T&, а другой с T&& в качестве перегрузки. T& печатает lvalue и T&& печатает rvalue , поэтому я знаю, какой из конструкторов используется. Я создаю 2 экземпляра класса в стеке и, к моему удивлению, оба используют перегрузку T&&.

#include <iostream>
#include <type_traits>
#include <utility>

template <class T> auto forward(T &&t) {
  if constexpr (std::is_lvalue_reference<T>::value) {
    return t;
  }
  return std::move(t);
}

template <class T> class Test {
public:
  Test(T &) { std::cout << "lvalue" << std::endl; };
  Test(T &&) { std::cout << "rvalue" << std::endl; };
};

int main() {
  int x = 5;
  Test<int> a(forward(3));
  Test<int> b(forward(x));
  return 0;
}

Я попытался использовать оригинальную функцию std::forward и реализовать ее, но оба раза она печатала rvalue x2. Что я делаю не так?

1 Ответ

14 голосов
/ 21 июня 2019

Ваша проблема связана с типом возврата forward. Вы используете auto в качестве типа возврата, который не выведет для вас ссылку. Это означает, что когда вы возвращаетесь, независимо от того, из какой ветви он возвращается, вы возвращаетесь по значению, что означает, что у вас есть значение.

Вам нужно decltype(auto), чтобы вы возвращали ссылку на rvalue или lvalue, в зависимости от оператора return. Использование

template <class T> decltype(auto) forward(T &&t) {
  if constexpr (std::is_lvalue_reference<T>::value)
    return t;
  else
    return std::move(t);
}

дает вам вывод:

rvalue
lvalue
...