c++ - 寻求对 std::forward 的澄清

标签 c++ c++11 std forward

引用std::forward

对于所有重载,返回类型已指定为 T&&(忽略 constexpr)。

但是在下面这个例子所附的描述中:

template<class T>
void wrapper(T&& arg) 
{
    // arg is always lvalue
    foo(std::forward<T>(arg)); // Forward as lvalue or as rvalue, depending on T
}
  • 如果对 wrapper() 的调用传递右值 std::string,则 T 是 推导为 std::string(不是 std::string&、const std::string& 或 std::string&&) 和 std::forward 确保右值引用是 传递给 foo。

  • 如果对 wrapper() 的调用传递了一个 const 左值 std::string,然后将 T 推导为 const std::string&,并且 std::forward 确保将 const 左值引用传递给 foo。

  • 如果对 wrapper() 的调用传递了一个非常量左值 std::string,则 T 推导为 std::string&,而 std::forward 确保非 const 左值引用传递给 foo。

在第一个之后的两个实例中,左值引用而不是右值引用(正如 T&& 所暗示的那样,这种理解是否正确?)已被记录为传递给 foo。

如果上面的理解是正确的,为什么返回值被指定为T&&

最佳答案

有区别

void f1(int&& a) {}

template<class T>
void f2(T&& a) {}

第一个版本是定义 f1 来处理右值。另一方面,第二个版本是一个模板函数,接受通用(或在某些引用中,转发)引用作为其参数。

要了解 std::forward 的机制,您应该使用不同的参数调用 f2,如:

#include <iostream>

template <class T> void f2(T &&a) { std::cout << __PRETTY_FUNCTION__ << '\n'; }

int main() {
  int a{5};

  f2(5);
  f2(a);

  return 0;
}

当您编译代码时,比如使用 g++,您会从程序中获得以下输出:

./a.out
void f2(T &&) [T = int]
void f2(T &&) [T = int &]

如您所见,在第一次调用中 T 被推断为 int,而在第二次调用中它被推断为 int &。由于引用折叠规则,正如您的问题的评论中已经提到的, T && 会给你 TT& && 会给你T&。简而言之,您观察 T&& 作为返回类型并不意味着函数返回右值引用。实际上,在模板函数中,&& 就像一个恒等运算符。当与 T& 组合时,它会给你 T&;否则,它会给你 T

有一个really nice talk在 CppCon2016 上,Arthur O'Dwyer 就此主题进行了讨论。也许您可以看一下它以了解模板类型推导规则,这将帮助您阐明 std::forward 行为。

关于c++ - 寻求对 std::forward 的澄清,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49215492/

相关文章:

C++:&(std::cout) 作为模板参数

c++ - 如何解决错误 : Cannot convert from 'OSamp::Weapon' to 'OSamp::Weapon' in C++ CLR

c++ - CRTP 派生类方法的返回类型的转发

c++ - 从 QObject 中删除动态属性

c++ - 继承在类外定义的运算符

C++:使用 "Undefined symbols for architecture x86_64"时出现 "std"错误

c++插入空 vector 不能使用大括号

c++ - 如何为 std::multimap 的给定键获取 "previous"项的迭代器(或值)?

c++ - 什么时候在空实例上调用成员函数会导致未定义的行为?

c++ - 将派生类传递到映射 C++