Skip to content

effective_modern_c++ Item24_P156_1

什么是万能引用

“万能引用”是 Scott Meyers 在他的书《Effective Modern C++》中引入的术语,用于描述某些模板参数的行为,这种模板参数可以绑定到几乎任何类型的参数,无论是 lvalue 还是 rvalue。正式的名称是"转发引用"(forwarding reference)。

一个万能引用的定义形式如下:

1template<typename T>
2void function(T&& arg);

这里,T&& 不仅仅是一个普通的右值引用。根据传递给函数的参数类型,它可能会表示一个 lvalue 引用或一个 rvalue 引用。这是通过模板参数推导和引用折叠规则实现的。

考虑以下情况:

  1. 传递 lvalue:
1int a = 42;
2function(a);  // 'a' is an lvalue

在这种情况下,T 被推导为 int&,所以 T&& 实际上变为 int& &&。根据引用折叠规则,它折叠为 int&。因此,arg 是一个指向 a 的 lvalue 引用。

  1. 传递 rvalue:
1function(42);  // '42' is an rvalue

在这种情况下,T 被推导为 int,所以 T&& 保持为 int&&。因此,arg 是一个 rvalue 引用。

万能引用的一个主要用途是实现“完美转发”,即在模板中将参数转发到其他函数,同时保持其原始值类别(lvalue 或 rvalue)。这通常与 std::forward 函数模板结合使用,如:

1template<typename T>
2void forwarder(T&& arg) {
3    anotherFunction(std::forward<T>(arg));
4}

这样,无论传递给 forwarder 的是 lvalue 还是 rvalue,都会以相同的方式转发给 anotherFunction

万能引用和右值引用的区别是什么

万能引用(也称为转发引用)和纯右值引用在语法上看起来很像,都使用 &&,但它们在语境和行为上有显著的不同。以下是它们之间的主要区别:

  1. 定义上的区别

    • 万能引用:只能作为函数模板参数,并且当其类型是以模板参数形式推导出来的时才被认为是万能引用。例如,template<typename T> void func(T&& arg); 这里的 T&& 是一个万能引用。
    • 右值引用:在非模板代码或模板代码中,如果引用的类型不是由推导确定的,那么它是一个纯右值引用。例如,int&& r = 5; 这里的 int&& 是一个纯右值引用。
  2. 行为上的区别

    • 万能引用:可以绑定到 lvalue 和 rvalue。模板类型推导和引用折叠规则决定了它最终的类型。如果传入的是 lvalue,T 会被推导为 lvalue 引用,使得 T&& 成为 lvalue 引用;如果传入的是 rvalue,T 被推导为非引用类型,使得 T&& 保持为 rvalue 引用。
    • 右值引用:只能绑定到临时对象或被转换为 rvalue 的对象。它的主要目的是支持移动语义和临时对象的生命周期延长。
  3. 用途上的区别

    • 万能引用:主要用于"完美转发",即无论传入的是 lvalue 还是 rvalue,都可以将其转发给另一个函数,同时保持原始的值类别。为此,通常与 std::forward 一起使用。
    • 右值引用:主要用于实现移动语义,即从一个对象“移动”其资源而不是复制。这在大对象或资源有限的场合(如动态分配的内存)中非常有用,因为移动通常比复制更有效率。

总的来说,万能引用是模板编程中的一个技巧,允许函数模板根据传入的参数类型动态地选择引用类型(lvalue 引用或 rvalue 引用),而右值引用是 C++11 引入的新型别,用于支持移动语义和对临时对象的高效操作。

Related Posts

  1. effective_modern_c++ Item24_P158_1