为什么将此类模板参数视为转发参考?

时间:2020-04-25 23:22:18

标签: c++ rvalue-reference type-deduction forwarding-reference

根据https://en.cppreference.com/w/cpp/language/reference,转发引用是

  1. 声明为右值引用的功能模板的功能参数。
  2. 自动&&。

这里https://isocpp.org/blog/2012/11/universal-references-in-c11-scott-meyers 斯科特·迈耶斯(Scott Meyers)解释说,尽管vector :: push_back(T && x)接受了T &&,但它不是通用参考。这只是一个普通的右值引用。

但是,我下面的代码可以编译并运行良好:

#include <iostream>

template<typename T>
class MyClass
{
public:
    void f(T&& x)
    {
        std::cout << __FUNCSIG__ << std::endl;
    }
};

int main()
{
    int i = 10;

    MyClass<int&> myClass1;
    myClass1.f(i); //void __thiscall MyClass<int &>::f(int &)

    MyClass<int&&> myClass2;
    myClass2.f(10); //void __thiscall MyClass<int &&>::f(int &&)
}

这听起来像T &&在这里被视为转发参考,因为f(T && x)接受左值引用和右值引用。但是f(T && x)是类模板成员;它不是独立的功能模板。这是否违反了我上面提到的转发参考定义?

<< \ ADD->

对于功能模板中的转发引用,功能模板本身也需要基于特定的类型T进行实例化。我们可以明确地表达这一点:

template<class T>
void f(T&& x)
{}

int main() {
    int i = 10;
    f<int&>(i); // argument is lvalue
    f<int&&>(10); // argument is rvalue
}

f <\ int&>和f <\ int &&>是上述功能模板的两个不同实例。它们也没有指向幕后的相同函数地址,类似于类模板实例化。当然,我们需要类对象才能使用其功能。

<-结束添加>

2 个答案:

答案 0 :(得分:3)

因为f(T&& x)接受左值引用和右值引用

不是。您不是在这里比较相同成员函数。 MyClass<int&>::f是一个仅接受左值的类的成员函数。同时,MyClass<int&&>::f另一个类的成员函数,并且仅接受右值。

类模板不是类。这是一个用来制作类的小甜饼。尽管这些专业化具有相似命名的成员函数,但在不同类中它们仍然是不同的函数。

如果您尝试传递MyClass<int&>::f一个右值,则您的代码将无法成功构建,

myClass1.f(10); // ERROR

Reference collapsing使生成的f接受不同值类别的引用,但是实例化该类后,该成员将仅接受特定值类别。它不会像在呼叫参考中那样转发在呼叫站点推断出的值类别。

答案 1 :(得分:0)

关于转发引用的事情是,它们在模板参数推导过程中自动 成为右值引用或左值引用。呼叫者不需要指定他们想要的。

在您的示例中,您已明确指定int&int&&,这将迫使f具有一种或另一种类型。然后,它会相应地采用左值或右值,但两者都不像转发引用可以:myClass1.f(10);myClass2.f(i);都格式错误。