C++ Primer 5th笔记(chap 16 模板和泛型编程)转发

Posted thefist11

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++ Primer 5th笔记(chap 16 模板和泛型编程)转发相关的知识,希望对你有一定的参考价值。

1. 转发

某些函数需要将其一个或多个实参连同类型不变地转发给其他函数。 因此需要保持被转发实参的所有性质, 包括实参类型是否是 const 的以及实参是左值还是右值。

//接受一个可调用对象和另外两个参数的模板
// 对 “翻转” 的参数调用给定的可调用对象
// flipl 是一个不完整的实现: 顶层 const 和引用丢失了
template <typename F, typename T1, typename T2> void flipl (F f , T1 tl, T2 t2)
{
   f (t2, t1);
}

这个函数一般情况下工作得很好, 但当我们希望用它调用一个接受引用参数的函数时就会出现问题:

void f (int v1, int &v2) // 注意 v2 是一个引用
{
   cout « v1 « "" << ++v2 « endl;
}


//f 改变了绑定到 v2 的实参的值。 但是, 如果我们通过 flipl 调用 f, f所做的改变就不会影响实参:
f(42, j); // f 改变了实参i
flipl (f, j, 42); // 通过 flipl 调用 f 不会改变 j

//等价于
void flipl (void(*fcn) (int, int & ), int t1, int t2);

1.1 定义能保持类型信息的函数参数

  • 通过翻转函数传递一个引用, 使其参数能保持给定实参的“ 左值性”。
  • 保持参数的 const 属性。

将一个函数参数定义为一个指向模板类型参数的右值引用 -> 保持其对应实参的所有类型信息。
使用引用参数( 无论是左值还是右值) -> 保持 const属性

eg. 在引用类型中的 const 是底层的。 如果我们将函数参数定义为 T1&&和 T2 &&, 通过引用折叠可以保持翻转实参的左值/右值属性

template <typename F, typename T1, typename T2> void flip2 (F f, T1 &&t1, T2 &&t2)
{
   f (t2, t1);
}

flip2解决了一半问题。 它对于接受一个左值引用的函数工作得很好,但不能用于接受右值引用参数的函数。 例如:

void g (int &&i, int & j )
{
	cout<< i << " " << j <<endl;
}

如果我们试图通过 fliP2调用g, 则参数 t2将被传递给g的右值引用参数。 即使我们传递一个右值给 flip2:

flip2 (g,i, 42); // 错误: 不能从一个左值实例化 int & &

2. 接受右值引用参数的模板函数

template <typename T> void f 3 (T && val)
{
   T t = val; // 拷贝还是绑定一个引用?
   t = fcn(t); //赋值只改变t还是既改变t又改变val?
   if (val == t) { /* ... */ } //若T是引用类型,则一直为true
}

右值引用通常用于两种情况:

  • 模板转发其实参
  • 模板被重载
template <typename T> void f (T &&) ;//绑定到非const右值
template <typename T> void f (const T &);//左值和const右值

3. std::forward

forward 传递 flip2 的参数,能保持原始实参的类型。

  • 必须通过显式模板实参来调用
  • forward 返回该显式实参类型的右值引用。 即, forward的返回类型是 T &&。

通常情况下, 我们使用 forward 传递那些定义为模板类型参数的右值引用的函数参数。 通过其返回类型上的引用折叠, forward 可以保持给定实参的左值/右值属性:

template <typename Typeintermediary (Type && arg)
{
   finalFcn (std::forward<Type>(arg));}

使用 Type 作为 forward 的显式模板实参类型, 它是从 arg 推断出来的。 由于arg 是一个模板类型参数的右值引用, Type 将表示传递给 arg的实参的所有类型信息。

  • 如果实参是一个右值, 则 Type 是一个普通( 非引用) 类型, forward将返回Type&&
  • 如果实参是一个左值, 则通过引用折叠, Type 本身是一个左值引用类型。 在此情况下, 返冋类型是一个指向左值引用类型的右值引用。 再次对 forward的返回类型进行引用折叠, 将返回一个左值引用类型。

使用 forward, 我们可以再次重写翻转函数:

template <typename F, typename T1, typename T2> void flip (F f, T1 &&t1, T2 &&t2)
{
   f(std::forward<T2> (t2), std::forward<T1> (t1));
}

如果我们调用 flip (g, i, 42 ) , i 将以 int &类型传递给 g, 42 将以 int &&类型传递给 g.

以上是关于C++ Primer 5th笔记(chap 16 模板和泛型编程)转发的主要内容,如果未能解决你的问题,请参考以下文章

C++ Primer 5th笔记(chap 16 模板和泛型编程)std::move

C++ Primer 5th笔记(chap 16 模板和泛型编程)模板特例化

C++ Primer 5th笔记(chap 16 模板和泛型编程)类模板特例化

C++ Primer 5th笔记(chap 16 模板和泛型编程)实例化

C++ Primer 5th笔记(chap 16 模板和泛型编程)可变参数模板

C++ Primer 5th笔记(chap 16 模板和泛型编程)模板实参