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 Type〉 intermediary (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 模板和泛型编程)实例化