【C++泛型学习笔记】万能引用、完美转发和常用标准库模板
学习参考书籍:王健伟《C++新经典:模板与泛型编程》
万能引用
万能引用是一种类型,同int一样。万能引用既可以接受左值,又可以接受右值。
右值引用:
1
2
int a = 3;
int &b = a; // 左值引用类型变量b左值引用:
1
int &&b = 3; // 右值引用类型变量b
左值和右值的区分:
- 可以取地址的(如存在内存中),有名字的(有标识符),非临时的就是左值;
- 不能取地址的(如存在寄存器中),没有名字的(没有标识符),临时的就是右值;
示例代码:
1 |
|
参数成为万能引用(也叫做未定义引用)类型必须满足如下条件:
- 必须是函数模板;
- 必须是发生了模板参数类型推断并且函数模板参数形如T&&。
在
T&&
前加const
关键字进行修饰,会将万能引用退化为右值引用。
完美转发
完美转发概念:从主函数中调用函数A,通过函数A调用函数B,这个过程叫做转发。函数A作为跳板函数,将主函数出入的参数传递给函数B。在普通转发过程中,参数的某些类型信息(如const属性、左值或右值属性)会丢失。而完美转发能够使在转发过程中参数的类型信息不丢失。
函数形参的完美转发:
1 |
|
上述完美转发实现方式为:通过一个函数模板A,可以把任意函数名B、任意类型参数传递给函数模板A,从而达到间接调用任意函数B的目的。std::forward<T>(t)
是C++标准库中的函数,作用是保持函数模板输入原始实参的左值性或右值性,实现函数形参的完美转发。
常用标准库模板
std::declval
作用:
- 将一个类型转换成右值引用类型。
- 配合decltype,让在decltype表达式中不必经过类类型的构造函数(不创建类对象)就能使用该类型的成员函数。
1
decltype(std::declval<A>().Afunc());
std::true_type和std::false_type
std::true_type/std::false_type
为类型别名(类类型),代表一个类型。1
2using true_type = integral_constant<bool, true>
using false_type = integral_constant<bool, false>作用:该类型在trait技术中应用广泛。
std::void_t
C++17别名模板,应用:
判断类中是否存在某个类型别名
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30struct NoInnerType
{
int m_i;
};
struct HaveInnerType
{
using type = int;
void func() {}
};
// 类模板泛化版本
template<typename T, typename U = std::void_t<>>
struct HasTypeMem : std::false_type
{
};
// 偏特化版本
template<typename T>
struct HasTypeMem<T, std::void_t<typename T::type>> : std::true_type
{
};
int main()
{
cout << HasTypeMem<NoInnerType>::value << endl; // 调用泛化版本
cout << HasTypeMem<HaveInnerType>::value << endl; // 调用偏特化版本
}判断类中是否存在某个成员变量
改写上述偏特化版本实现,其他代码不变
1
2
3
4
5
6// 偏特化版本
template<typename T>
struct HasTypeMem<T, std::void_t<decltype(T::m_i)> : std::true_type
{
};判断类中是否存在某个成员函数
1
struct HasTypeMem<T, std::void_t<decltype(std::declval<T>().func())> : std::true_type
std::conditional
C++11类模板,表现编译期的分支逻辑。实现代码如下:
1
2
3
4
5
6
7
8
9
10
11template<bool b, class T, class U>
struct conditional
{
using type = T;
};
template<class T, class U>
struct conditional<false, T, U>
{
using type = U;
};std::conditional<true, A, B>::type
返回A;std::conditional<false, A, B>::type
返回B,类似于if-then-else
逻辑。std::function
可调用对象包装器,C++11类模板。
std::remove_all_extents
C++11类模板,功能为把一个数组中的数组类型部分移除,只保留元素类型。即int[10]变为int。
1
2int a[10];
std::remove_all_extents<decltype(a)>;
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!