Lvalue, Rvalue:

В C++ lvalue и rvalue — это основные определения того, где можно использовать выражение. Если его можно использовать только справа от уравнения, это называется rvalue, в противном случае, если его можно использовать с обеих сторон, это называется lvalue.

Примеры lvalue:
— Имена переменных
— Элементы массива
— Результаты вызова функций
— Выражения индексов
— Выражения доступа к членам

Примеры rvalue:
— литералы
— результаты большинства операторов
— вызовы функций, возвращающие не ссылочные типы

Ссылки Rvalue передаются с двумя амперсандами (&&), поскольку они могут привязываться только к временным объектам. Это полезно для функций, которым необходимо создавать новые объекты, таких как конструкторы и операторы перемещения присваивания.

std::string str = std::move("Hello, world!");

В приведенном выше примере функция std::move() преобразует строковый литерал rvalue в ссылку rvalue, которую затем можно привязать к объекту str. Это позволяет конструктору std::string создать новый объект из временного строкового литерала.

Идеальная переадресация:

Это метод в C++, который позволяет шаблону функции пересылать свои аргументы другой функции, сохраняя при этом природу lvalue или rvalue исходных аргументов функции. Это может быть полезно для различных целей, например, для предотвращения чрезмерного копирования или перемещения объектов или для того, чтобы позволить автору шаблона написать один шаблон функции, который можно использовать как с lvalue, так и с rvalue.

В C++ существует специальный метод с именем std::forward, который помогает сохранить природу lvalue или rvalue при передаче через функции.

Это вспомогательная функция, позволяющая идеальную пересылку аргументов, взятых как ссылки на rvalue, в выведенные типы, сохраняя любую потенциальную семантику перемещения. em> участвует.

Например:

// forward example
#include <utility>      // std::forward
#include <iostream>     // std::cout

// function with lvalue and rvalue reference overloads:
void overloaded (const int& x) {std::cout << "[lvalue]";}
void overloaded (int&& x) {std::cout << "[rvalue]";}

// function template taking rvalue reference to deduced type:
template <class T> void fn (T&& x) {
  overloaded (x);                   // always an lvalue
  overloaded (std::forward<T>(x));  // rvalue if argument is rvalue
}

int main () {
  int a;

  std::cout << "calling fn with lvalue: ";
  fn (a); // ----- 1
  std::cout << '\n';

  std::cout << "calling fn with rvalue: ";
  fn (0); // ----- 2
  std::cout << '\n';

  return 0;
}

Здесь для первого вызова это вызов lvalue, поэтому будет напечатан [lvalue]. Для второго вызова это вызов rvalue, поэтому он выведет [rvalue] из перегруженных функций.

Надеюсь, эти детали помогут правильно понять lvalue, rvalue.

Ссылка:
- https://en.cppreference.com/w/cpp/utility/forward