std::foward 的第二次重载(cppreference.com 上的示例)

Second overload of std::foward (example on cppreference.com)

我知道 std::forward 的第二个重载:

template< class T >
constexpr T&& forward( std::remove_reference_t<T>&& t ) noexcept;

用于右值(如 Howard Hinnant 在他的回答中所述:

有一个在 cppreference.com 处使用此重载的示例(Praetorian 在 中也提到了):

  1. Forwards rvalues as rvalues and prohibits forwarding of rvalues as lvalues This overload makes it possible to forward a result of an expression (such as function call), which may be rvalue or lvalue, as the original value category of a forwarding reference argument.

For example, if a wrapper does not just forward its argument, but calls a member function on the argument, and forwards its result:

// transforming wrapper 
template<class T>
void wrapper(T&& arg)
{
    foo(forward<decltype(forward<T>(arg).get())>(forward<T>(arg).get()));
}

where the type of arg may be

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())>

Cppreference 声明:

This overload makes it possible to forward a result of an expression (such as function call), which may be rvalue or lvalue, as the original value category of a forwarding reference argument.

举个例子:

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()));

仍然,我无法理解为什么有人需要添加外前锋。

编辑: 编辑移至后续问题:

Why is the outer forward forward<decltype(forward<T>(arg).get())> even needed?

It's not. The expression already is of its own correct value category. In C++17 (when returning by value bigger types) it's even a pessimization. All it does is turn a potential prvalue into an xvalue, 。我很想说这是货物崇拜编程。