在 C++ 中,将左值完美转发到函数模板的正确方法是什么?

Gas*_*rdP 1 c++ templates perfect-forwarding c++11

接受完美转发的参数包的正确方法是什么,以便它可以采用任何类型并简单地转发它们?以下代码适用于常规类型,但不适用于指针类型:

template<typename ...A>
void b(A &&... args)
{}

template<typename ...A>
void a(A &&... args)
{
    b(std::forward<A>(args)...);
}


int main() {

    // ok
    a<int>(5);

    // error: cannot bind rvalue reference of type ‘int*&&’ to lvalue of type ‘int*’
    int *foo = nullptr;
    a<int*>(foo);

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

[编辑] 感谢您的快速而精彩的回复!我过于简化了 - 这是我试图解决的问题的一个更接近的例子:

#include <iostream>
using namespace std;

template<typename F>
struct fun;

template<typename F, typename ...A>
struct fun<F(A...)>
{
    void b(A &&... args)
    {}
    
    void a(A &&... args)
    {
        b(std::forward<A>(args)...);
    }
};

int main() {

    // ok
    fun<void(int)> f1;
    f1.a(5);

    // error: cannot bind 'int' lvalue to 'int&&'
    fun<void(int)> f2;
    int x = 5;
    f2.a(x);

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,我没有办法让模板自动调整......知道如何实现吗?

[编辑 2] 正如评论中所指出的,这与指针无关,我更新了我的示例以简单地使用 lvalue

son*_*yao 7

您不应显式指定模板参数;这只是防止模板参数推导与转发引用一起工作,并产生意外的结果。

a<int>(5);    // A is specified as int then function parameter's type is int&&.
              // 5 is an rvalue and could be bound to int&&

a<int*>(foo); // A is specified as int* then function parameter's type is int* &&.
              // foo is an lvalue and couldn't be bound to int* &&
Run Code Online (Sandbox Code Playgroud)

只是

a(5);   // 5 is rvalue, then A is deduced as int and function parameter's type collapses to int&&

int *foo = nullptr;
a(foo); // foo is lvalue, then A is deduced as int* & and function parameter's type collapses to int* &
Run Code Online (Sandbox Code Playgroud)

编辑

首先,成员函数ba都不是模板,它们的参数根本没有声明为转发引用

该代码不起作用,因为

fun<void(int)> f2;
int x = 5;
f2.a(x); // A is specified as int then function parameter's type is int &&.
         // x is an lvalue and couldn't be bound to int &&
Run Code Online (Sandbox Code Playgroud)

我不确定您的意图,您可以将其更改为

fun<void(int&)> f2;
//          ^
int x = 5;
f2.a(x); // A is specified as int& then function parameter's type collapses to int&.
         // x is an lvalue and could be bound to int&
Run Code Online (Sandbox Code Playgroud)

或者使它们功能模板并仍然应用转发引用。

template <typename... T>
void b(T &&... args)
{}

template <typename... T>
void a(T &&... args)
{
    b(std::forward<T>(args)...);
}
Run Code Online (Sandbox Code Playgroud)

  • 或者(如果您坚持使用显式模板参数),您可以编写“a&lt;int*&amp;&gt;(foo);”。 (2认同)