Я знаю, что вторая перегрузка std::forward
:
template< class T >
constexpr T&& forward( std::remove_reference_t<T>&& t ) noexcept;
используется для rvalue (как заявил Говард Хиннант в своем ответе: Как std::forward получает правильный аргумент?)
Есть пример использования этой перегрузки на cppreference.com (это также упоминается в Как std::forward получает правильный аргумент? от Praetorian):
- Пересылает rvalue как rvalue и запрещает переадресацию rvalue как lvalue. Эта перегрузка позволяет пересылать результат выражения (например, вызова функции), который может быть rvalue или lvalue, в качестве категории исходного значения аргумента пересылаемой ссылки .
Например, если оболочка не просто пересылает свой аргумент, но вызывает функцию-член для аргумента и пересылает свой результат:
// transforming wrapper template<class T> void wrapper(T&& arg) { foo(forward<decltype(forward<T>(arg).get())>(forward<T>(arg).get())); }
где тип arg может быть
struct Arg { int i = 1; int get() && { return i; } // call to this overload is rvalue int& get() & { return i; } // call to this overload is lvalue };
Я действительно не понимаю этот пример. Зачем вообще нужен внешний форвард forward<decltype(forward<T>(arg).get())>
?
Состояния Cpppreference:
Эта перегрузка позволяет пересылать результат выражения (например, вызова функции), который может быть rvalue или lvalue, в качестве категории исходного значения аргумента ссылки пересылки.
Например:
void func(int& lvalue)
{
std::cout << "I got an lvalue!" << std::endl;
}
void func(int&& rvalue)
{
std::cout << "I got an rvalue!" << std::endl;
}
template <typename T>
T&& myForward(typename std::remove_reference_t<T>& t)
{
return static_cast<T&&>(t);
}
struct foo
{
int i = 42;
int& get()& { return i; }
int get()&& { return i; }
};
template <typename T>
void wrapper(T&& t)
{
func(myForward<T>(t).get());
}
int main()
{
foo f;
wrapper(f);
wrapper(foo());
return 0;
}
Это печатает:
I got an lvalue!
I got an rvalue!
просто отлично, без внешней переадресации, в то время как он также пересылает «результат выражения [...] как исходную категорию значения аргумента пересылаемой ссылки». Ему даже не нужна вторая перегрузка std::forward
. Эта перегрузка необходима только при вызове func()
следующим образом:
func(myForward<decltype(myForward<T>(t).get())>(myForward<T>(t).get()));
Тем не менее, я не могу понять, зачем кому-то нужно добавлять внешний форвард.
Изменить: Изменить перемещено в последующий вопрос: Перегрузка RValue-reference std::forward потенциально может привести к висячей ссылке?
Вы цитируете какой-то неизвестный источник. Поиск ссылки над цитатой, содержащей «пример, если оболочка не работает» для этой строки, не показывает эту строку? Предполагается ли, что приведенный выше раздел «в кавычках» является цитатой или он просто неправильно отформатирован?
Вы перефразируете, делая вид, что цитируете? Я запутался? Вы ошиблись ссылкой?
Ах, вы цитируете en.cppreference.com/w/cpp/utility/forward
Вероятно, это просто пример того, что может произойти в сложных сценариях программирования шаблонов. Чтобы упростить еще больше: мы, вероятно, хотим, чтобы код вида
myForward<int>(42);
компилировался, и он не будет компилироваться без перегрузкиstd::remove_reference_t<T>&& t
.Дубликат: coderhelper.com/q/41543571/5376789