可以实现在编译器计算,查询,判断转换和选择
用于降低圈复杂度
将编译器常量包装为一个类型的type_traits----integral_constant
integral_constant中有一个常量成员变量value,可以通过integral_constant::value获取
template
struct Test : std::integral_constant {
// 相当于
// constexpr int value = 2;
};
int main()
{
std::cout << Test::value << endl;
}
常用的已定义的traits很多,都是由integral_constant派生而来的。
https://en.cppreference.com/w/cpp/types
std::is_XXX::value
是否为true来判断模板类型是否为目标类型。template
struct is_integral; // is_integral是用来检查T是否无符号整型
// 如果T是的话,则is_integral::value是true
#include
int main() {
cout << std::is_const::value << endl; // 1
cout << std::is_const::value << endl; // 0
}
template
struct is_same;
cout << is_same::value << endl; // 1
cout << is_same::value << endl; // 0
template
struct is_same;
template
struct is_convertible;
XXX::type表示转换后的类型
对const的修改
add_const
remove_const
对引用
remove_reference
add_lvalue_reference
add_rvalue_reference
移除数组顶层的维度
remove_extent
移除数组所有维度
remove_all_extents
remove_pointer
add_pointer
移除引用和cv符,对函数而言是添加函数指针
decay
....
如果B为true,则conditional::type为T
template
struct conditional;
declval
result_of
enable_if
声明时,class后面加…
template
void f(T... args) {
cout << sizeof...(args) << endl;
}
f(); // 0
f(1, 2); // 2
f(1, 2.5, ""); // 3
展开参数包:
// 终止函数
void f() {
cout << "end" << endl;
}
// 展开函数,设定头和剩余参数
template
void f(T head, Args... rest) {
cout << "args:" << head << endl;
f(rest...); // 递归调用自己,最后一次调用终止函数
}
int main() {
f(1, 2.5, "adda");
}
初始化列表方式:
template
void expand(Args... args) {
// 通过初始化列表,初始化一个变长数组
int arr[] = { args... }; // 1,2,3,4
}
expand(1, 2, 3, 4);
逗号表达式:
实现在初始化数组的同时,操作参数
// 处理参数包中的每个参数的函数
template
void print(T args) {
cout << args << endl;
}
template
void expand(Args... args) {
// 在初始化的同时,执行print函数对每个参数进行操作
int arr[] = { (print(args), args)... };
// 也可以使用initializer_list代替数组
std::initializer_list{ (print(args), args)...};
// 使用匿名函数代替print函数
// 匿名函数后的()代表着 空参 执行lamdba表达式
std::initializer_list{ ([&](){ cout << args << endl; }(), args)...};
// 也可以不存参数包直接传
print(args...);
}
expand(1, 2, 3, 4);
关于逗号表达式
// 按顺序执行逗号前面的表达式
// 1. a = b
// 2. d = c
d = ( a = b , c)
一般需要定义2~3个类,包括类声明和特化模板类
以下例子用来计算参数类型的字节总和
// 1. 前向声明,声明Sum是可变参数模板类
template
struct Sum;
// 2.类的定义, 递归调用自己
template
struct Sum {
enum { value = Sum::value + Sum::value };
};
// 3. 特化模板类,终止函数。参数只有一个时,value为此类型大小(只是个例子)
// 也可以写成参数只有0个或者2个时....(终止函数的写法很多)
template
struct Sum {
enum { value = sizeof(Last) };
};
cout << Sum::value; // 9