std::forward 表现不同

std::forward acting differently

我目前正在学习 C++ 中的完美转发,我遇到了一些让我困惑的事情。很确定这是愚蠢的事情。当我在左值上使用 std::forward 时,它使用了右值函数。这是一个非常糟糕的解释,所以我只展示代码。

#include <iostream>

void check(int&& other) {
    std::cout << "Rvalue" << std::endl;
}

void check(int& other) {
    std::cout << "Lvalue" << std::endl;
}

void call(int& other) {
    check(std::forward<int>(other));
}

int main()
{
    int i = 4;
    call(i);
}

这会输出“右值”。请帮助我了解原因。

std::forward() 并不完全是魔法。这是必须为其提供具有适当引用类别(右值引用、左值引用、无引用)的适当类型的原因之一。

通常,您从模板参数中获取类型。如果它是一个 auto&& 参数(C++14 lambda、C++20 缩写模板或概念的使用),则使用 decltype() 从函数参数中获取它。

手动指定它有效,但违背了使用该功能的精神。 std::move() 或者参数本身在这种情况下更容易使用,具体取决于您指定的模板参数。

并且由于引用折叠和 std::forward() 的定义方式,TypeType&& 都会导致右值引用,而 Type& 会导致左值-参考。

模板使用“完美转发”,即:

template<typename T>
void func(T && arg)
{
    func2(std::forward<T>(arg));
}

在模板上下文之外,最终结果会发生巨大变化。 std::forward 所做的只是 return static_cast<T &&>,因此您的 call 函数只不过是:

void call(int& other) {
    check(static_cast<int &&>(other));
}

因此你得到一个右值。这在模板中工作不同的原因是因为 && 模板参数是 转发引用 (左值或一个右值推导的引用,取决于在该参数中删除的内容),并且因为 reference collapsing rules。简而言之,当在模板上下文中使用时,最终结果是:

  1. T 被推断为左值或右值引用,具体取决于参数是什么。

  2. 如果T是左值引用,static_cast<T &&>的结果是左值引用,如果T是右值引用,则结果是右值引用,由于引用折叠规则。

最终结果是转发了相同类型的引用。但这仅适用于模板上下文,因为它需要转发引用语义和引用折叠规则才能正常工作恰到好处