模板中右值引用和 const 左值引用之间的重载

Posted

技术标签:

【中文标题】模板中右值引用和 const 左值引用之间的重载【英文标题】:Overload between rvalue reference and const lvalue reference in template 【发布时间】:2015-01-08 08:38:04 【问题描述】:

我想根据参数是否为临时对象来重载两个函数,所以我写了这样的代码:

#include <iostream>

void f(int &&)

  std::cout << "&&" << std::endl;


void f(const int&)

  std::cout << "const &" << std::endl;


int main()

  int i;
  f(i);
  f(i + 1);

它正确地输出:

const &
&&

但是,当我将代码更改为使用这样的模板时:

#include <iostream>

template <typename T>
void f(T &&)

  std::cout << "&&" << std::endl;


template <typename T>
void f(const T&)

  std::cout << "const &" << std::endl;


int main()

  int i;
  f(i);
  f(i + 1);

输出变成:

&&
&&

有什么问题?使用模板时如何优化可移动临时对象?

编辑:

其实这是我看C++ Primer时的测试代码。它说:

template <typename T> void f(T&&);       // binds to nonconst rvalues
template <typename T> void f(const T&);  // lvalues and const rvalues

经过我的实验,这本书似乎在这里犯了一个错误。

【问题讨论】:

“如何在使用模板时优化可移动临时对象”是什么意思T&amp;&amp; 本身是最佳的,因为它绑定到所有内容并允许您恢复用作参数的表达式的值类别 @PiotrS。例如,如果它将变量 i 绑定到 const T&,并将表达式 i + 1 绑定到 T&&,那么我可以从 i + 1 生成的临时对象中移动资源。 这就是为什么有条件移动,即std::forward&lt;T&gt;,取决于为T 推导出的类型,它要么移动,要么根本不移动。您不必为右值显式使用std::move。请注意T&amp;&amp; 其中T 是一个类型模板参数是一个转发引用,其行为不同于常规右值引用 @PiotrS。当我对函数参数使用右值引用时,我希望这个参数总是绑定到临时对象。但在这种情况下,它也绑定到变量。 T&amp;&amp; with T 是一个类型模板参数是一个转发引用,而不是一个右值引用,阳光下的一切都可以受转发参考约束 【参考方案1】:
template <typename T>
void f(T &&)

  std::cout << "&&" << std::endl;

使用 universal 转发引用并允许任何类型的引用折叠。

你必须使用T 和没有推导上下文来将你的代码包装到一个结构中:

template <typename T>
struct helper


    void f(T &&)
    
      std::cout << "&&" << std::endl;
    

    void f(const T&)
    
      std::cout << "const &" << std::endl;
    

;

template <typename T>
void f(T &&t)

     helper<typename std::decay<T>::type>().f(std::forward<T>(t));

Live example

【讨论】:

std::decay, std::forward,... 在我理解这种行为之前,我似乎必须了解更多。 -_-||

以上是关于模板中右值引用和 const 左值引用之间的重载的主要内容,如果未能解决你的问题,请参考以下文章

重新理解C11的右值引用

在 C++ 中将右值引用转换为临时参数到 const 左值返回的正确方法

为啥在特殊成员函数中将 r 值绑定到 const 左值引用是非法的?

C++11 ——— 右值引用和移动语义

C++左值引用和右值引用

左值引用与右值引用