模板元编程
模板元编程
oss、mysql中大量使用
模板元的数据不能是运行期的变量,只能是编译期的常量
语法不能用if、else、for等
一般和类型重定义、枚举、继承、模板偏特化等配合使用
编译前准备
typedef/using定义源数据
enum、static、枚举和静态,const定义编译器的整数常量
T、Args…声明源数据类型
::解析类型作用域,获取计算结果
template模板,定义源数据
模板元编程里不能使用if else for,需要使用时可以用其他方式实现
if、else可以通过三目运算符实现
for可以通过递归、重载、模板(偏特化)实现
c++11的 type_traits库
提供了大量的在编译期间 计算、查询、判断、转换、选择
const和constexpr
const告诉编译器在初始化,不能被赋值和修改,但是可以通过溢出对值进行修改
constexpr告诉编译器当前的常量表达式可以被优化,限制比const多
class.h
#pragma once
template<class T,T v>//把v当作参数传进来了
struct Fconst1
{
static constexpr T value = v;//以使用Fconst1来创建一个类型为T,值为v的常量
};
//template<int v1, int v2>//会报错
//struct Fconst2
//{
// static constexpr T value = v1 + v2;
//
//};
//template<class T1,T1 v1,class T2,T2 v2>//会报错
//struct fconst2
//{
// static constexpr t value = v1 + v2;
//
//};
template<class T>
struct RemoveConst
{
using Type = T;
};
template<class T>
struct RemoveConst<const T>
{
using Type = T;
};
//判断两个类型是否是一样的
template<bool v>
using bool_temp = Fconst1<bool, v>;
//参数不相等走此
template<class,class>
constexpr bool isSame_V = false;
//两个一样走此
template<class T1>
constexpr bool isSame_V<T1, T1> = true;
//使用了模板特化,当两个类型一样时,使用constexpr bool isSame_V<T1,T1> = true;
template<class T1,class T2>
struct isSame :bool_temp<isSame_V<T1, T2>> {};
学习.cpp
#include <iostream>
#include"advanced.h"
#include"class.h"
struct FTestA
{
};
struct FTestB
{
FTestB(int a, int b)
{
}
int print(int a, int b)
{
printf("%i %i", a, b);
return a + b;
}
};
int main()
{
/*
FTestA* p = CreateObject<FTestA>();
FTestB* p2 = CreateObject<FTestB>(1,2);
auto NewFunction = CreateDelegate(p2, &FTestB::print);
int a = NewFunction(1, 2);
cout << "\n" << a << endl;
*/
int v = Fconst1<int, 1>::value;
//Fconst1模板结构体用于将1作为值参数v传递给类型参数T,然后使用value静态成员变量获取这个值。
RemoveConst<const int>::Type a1;
//使用RemoveConst模板结构体来移除const修饰符。在这个例子中,传递的类型是const int,所以使用RemoveConst<const int>会返回一个没有const修饰符的int类型。
a1 = 100;
//int v = Fconst2<1, 2>::value;//会报错
//比较类型是否一样
bool TT = isSame<int, float>::value;
//使用isSame模板结构体来判断int和float两个类型是否相同。在这个例子中,它们是不同的类型,所以TT的值为false
return 0;
}
type_traits的类型判定
is_same、is_class、is_enum、is_integra、is_floating_point、is_pointer、is_lvalue_reference、is_rvalue_reference、is_function、is_member_function_pointer、is_array、is_arithmetic、is_abstract
类型相同否
std::is_same比较给定的类型是否相同,如果相同返回1,如果不相同返回0
类
std::is_class判断给定的类型是否是类类型,如果是返回1,如果不是返回0
枚举
std::is_enum判断给定的类型是否是枚举类型,如果是返回1,如果不是返回0
整型
std::is_integral判断给定的类型是否是整型,如果是返回1,如果不是返回0
浮点型
std::is_floating_point判断给定的类型是否是浮点型,如果是返回1,如果不是返回0
指针
std::is_pointer判断给定的类型是否是指针,如果是返回1,如果不是返回0
左值
is_lvalue_reference判断给定的类型是否是左值,如果是返回1,如果不是返回0
右值
is_rvalue_reference判断给定的类型是否是右值,如果是返回1,如果不是返回0
函数
is_function判断给定的类型是否是函数,如果是返回1,如果不是返回0
成员函数
is_member_function_pointer判断给定的类型是否是成员函数,如果是返回1,如果不是返回0
容器
is_array判断给定的类型是否是容器,如果是返回1,如果不是返回0
整形或浮点型
is_arithmetic判断给定的类型是否是整型或浮点型,如果是返回1,如果不是返回0
抽象类
is_abstract判断给定的类型是否是抽象类,如果是返回1,如果不是返回0
学习.cpp
(测试案例,没屁用)
#include <iostream>
#include"advanced.h"
#include"class.h"
#include <type_traits>
#include <vector>
struct FTestA
{
};
struct FTestB
{
FTestB(int a, int b)
{
}
int print(int a, int b)
{
printf("%i %i", a, b);
return a + b;
}
};
class A
{
public:
struct C
{
int a;
};
};
enum ETestEnum
{
AA,BB,
};
class FInterface
{
public:
virtual void Init() = 0;
};
int main()
{
int v = Fconst1<int, 1>::value;
RemoveConst<const int>::Type a1;
a1 = 100;
bool TT = isSame<int, float>::value;
auto Test1 = []()
{
cout << "Test1" << endl;
};
//std::is_same比较给定的类型是否相同,如果相同返回1,如果不相同返回0
cout << endl;
cout << std::is_same<int, int>::value << endl;//输出结果:1
cout << endl;
//std::is_class判断给定的类型是否是类类型,如果是返回1,如果不是返回0
cout << std::is_class<FTestB>::value << endl;//输出结果:1
cout << std::is_class<A>::value << endl;//输出结果:1
cout << std::is_class<int>::value << endl;//输出结果:0
cout << std::is_class<float>::value << endl;//输出结果:0
cout << std::is_class<ETestEnum>::value << endl;//输出结果:0//判断枚举不是类类型
cout << endl;
//std::is_enum判断给定的类型是否是枚举类型,如果是返回1,如果不是返回0
cout << std::is_enum<FTestB>::value << endl;//输出结果:0
cout << std::is_enum<A>::value << endl;//输出结果:0
cout << std::is_enum<int>::value << endl;//输出结果:0
cout << std::is_enum<float>::value << endl;//输出结果:0
cout << std::is_enum<ETestEnum>::value << endl;//输出结果:1
cout << endl;
//std::is_integral判断给定的类型是否是整形,如果是返回1,如果不是返回0
cout << std::is_integral<FTestB>::value << endl;//输出结果:0
cout << std::is_integral<A>::value << endl;//输出结果:0
cout << std::is_integral<int>::value << endl;//输出结果:1
cout << std::is_integral<float>::value << endl;//输出结果:0
cout << std::is_integral<ETestEnum>::value << endl;//输出结果:0
cout << endl;
//std::is_floating_point判断给定的类型是否是浮点形,如果是返回1,如果不是返回0
cout << std::is_floating_point<FTestB>::value << endl;//输出结果:0
cout << std::is_floating_point<A>::value << endl;//输出结果:0
cout << std::is_floating_point<int>::value << endl;//输出结果:0
cout << std::is_floating_point<float>::value << endl;//输出结果:1
cout << std::is_floating_point<ETestEnum>::value << endl;//输出结果:0
cout << std::is_floating_point<FTestB*>::value << endl;//输出结果:0
cout << std::is_floating_point<A*>::value << endl;//输出结果:0
cout << std::is_floating_point<int*>::value << endl;//输出结果:0
cout << std::is_floating_point<float*>::value << endl;//输出结果:0//float类型指针也不是
cout << std::is_floating_point<ETestEnum*>::value << endl;//输出结果:0
cout << endl;
//std::is_pointer判断给定的类型是否是指针,如果是返回1,如果不是返回0
cout << std::is_pointer<FTestB>::value << endl;//输出结果:0
cout << std::is_pointer<A>::value << endl;//输出结果:0
cout << std::is_pointer<int>::value << endl;//输出结果:0
cout << std::is_pointer<float>::value << endl;//输出结果:0
cout << std::is_pointer<ETestEnum>::value << endl;//输出结果:0
cout << std::is_pointer<FTestB*>::value << endl;//输出结果:1
cout << std::is_pointer<A*>::value << endl;//输出结果:1
cout << std::is_pointer<int*>::value << endl;//输出结果:1
cout << std::is_pointer<float*>::value << endl;//输出结果:1
cout << std::is_pointer<ETestEnum*>::value << endl;//输出结果:1
cout << endl;
//&左值 &&右值
//is_lvalue_reference判断给定的类型是否是左值,如果是返回1,如果不是返回0
cout << std::is_lvalue_reference<FTestB>::value << endl;//输出结果:0
cout << std::is_lvalue_reference<A>::value << endl;//输出结果:0
cout << std::is_lvalue_reference<int>::value << endl;//输出结果:0
cout << std::is_lvalue_reference<float>::value << endl;//输出结果:0
cout << std::is_lvalue_reference<ETestEnum>::value << endl;//输出结果:0
cout << std::is_lvalue_reference<FTestB&>::value << endl;//输出结果:1
cout << std::is_lvalue_reference<A&>::value << endl;//输出结果:1
cout << std::is_lvalue_reference<int&>::value << endl;//输出结果:1
cout << std::is_lvalue_reference<float&>::value << endl;//输出结果:1
cout << std::is_lvalue_reference<ETestEnum&>::value << endl;//输出结果:1
cout << std::is_lvalue_reference<FTestB&&>::value << endl;//输出结果:0
cout << std::is_lvalue_reference<A&&>::value << endl;//输出结果:0
cout << std::is_lvalue_reference<int&&>::value << endl;//输出结果:0
cout << std::is_lvalue_reference<float&&>::value << endl;//输出结果:0
cout << std::is_lvalue_reference<ETestEnum&&>::value << endl;//输出结果:0
cout << endl;
//is_rvalue_reference判断给定的类型是否是右值,如果是返回1,如果不是返回0
cout << std::is_rvalue_reference<FTestB>::value << endl;//输出结果:0
cout << std::is_rvalue_reference<A>::value << endl;//输出结果:0
cout << std::is_rvalue_reference<int>::value << endl;//输出结果:0
cout << std::is_rvalue_reference<float>::value << endl;//输出结果:0
cout << std::is_rvalue_reference<ETestEnum>::value << endl;//输出结果:0
cout << std::is_rvalue_reference<FTestB&>::value << endl;//输出结果:0
cout << std::is_rvalue_reference<A&>::value << endl;//输出结果:0
cout << std::is_rvalue_reference<int&>::value << endl;//输出结果:0
cout << std::is_rvalue_reference<float&>::value << endl;//输出结果:0
cout << std::is_rvalue_reference<ETestEnum&>::value << endl;//输出结果:0
cout << std::is_rvalue_reference<FTestB&&>::value << endl;//输出结果:1
cout << std::is_rvalue_reference<A&&>::value << endl;//输出结果:1
cout << std::is_rvalue_reference<int&&>::value << endl;//输出结果:1
cout << std::is_rvalue_reference<float&&>::value << endl;//输出结果:1
cout << std::is_rvalue_reference<ETestEnum&&>::value << endl;//输出结果:1
cout << endl;
//is_function判断给定的类型是否是函数,如果是返回1,如果不是返回0
cout << std::is_function<FTestB>::value << endl;//输出结果:0
cout << std::is_function<A>::value << endl;//输出结果:0
cout << std::is_function<int>::value << endl;//输出结果:0
cout << std::is_function<float>::value << endl;//输出结果:0
cout << std::is_function<ETestEnum>::value << endl;//输出结果:0
cout << std::is_function<void(int a)>::value << endl;//输出结果:1
cout << std::is_function<void(int ,int)>::value << endl;//输出结果:1
cout << std::is_function<void(...)>::value << endl;//输出结果:1
cout << endl;
//is_member_function_pointer判断给定的类型是否是成员函数,如果是返回1,如果不是返回0
cout << std::is_member_function_pointer<FTestB>::value << endl;//输出结果:0
cout << std::is_member_function_pointer<A>::value << endl;//输出结果:0
cout << std::is_member_function_pointer<int>::value << endl;//输出结果:0
cout << std::is_member_function_pointer<float>::value << endl;//输出结果:0
cout << std::is_member_function_pointer<ETestEnum>::value << endl;//输出结果:0
cout << std::is_member_function_pointer<void(int a)>::value << endl;//输出结果:0
cout << std::is_member_function_pointer<void(int, int)>::value << endl;//输出结果:0
cout << std::is_member_function_pointer<void(...)>::value << endl;//输出结果:0
cout << std::is_member_function_pointer<float(A::C::*)>::value << endl;//输出结果:0//成员对象指针
cout << std::is_member_function_pointer<double(A::C::*)()>::value << endl;//输出结果:1//成员对象函数
cout << endl;
//is_array判断给定的类型是否是容器,如果是返回1,如果不是返回0
cout << std::is_array<FTestB>::value << endl;//输出结果:0
cout << std::is_array<A>::value << endl;//输出结果:0
cout << std::is_array<int>::value << endl;//输出结果:0
cout << std::is_array<float>::value << endl;//输出结果:0
cout << std::is_array<ETestEnum>::value << endl;//输出结果:0
cout << std::is_array<void(int a)>::value << endl;//输出结果:0
cout << std::is_array<void(int, int)>::value << endl;//输出结果:0
cout << std::is_array<void(...)>::value << endl;//输出结果:0
cout << std::is_array<float(A::C::*)>::value << endl;//输出结果:0
cout << std::is_array<double(A::C::*)()>::value << endl;//输出结果:0
cout << std::is_array<vector<int>>::value << endl;//输出结果:0
cout << std::is_array<int[]>::value << endl;//输出结果:1
cout << endl;
//is_arithmetic判断给定的类型是否是整型或浮点型,如果是返回1,如果不是返回0
cout << std::is_arithmetic<FTestB>::value << endl;//输出结果:0
cout << std::is_arithmetic<A>::value << endl;//输出结果:0
cout << std::is_arithmetic<int>::value << endl;//输出结果:1
cout << std::is_arithmetic<float>::value << endl;//输出结果:1
cout << std::is_arithmetic<ETestEnum>::value << endl;//输出结果:0
cout << std::is_arithmetic<void(int a)>::value << endl;//输出结果:0
cout << std::is_arithmetic<void(int, int)>::value << endl;//输出结果:0
cout << std::is_arithmetic<void(...)>::value << endl;//输出结果:0
cout << std::is_arithmetic<float(A::C::*)>::value << endl;//输出结果:0
cout << std::is_arithmetic<double(A::C::*)()>::value << endl;//输出结果:0
cout << std::is_arithmetic<vector<int>>::value << endl;//输出结果:0
cout << std::is_arithmetic<int[]>::value << endl;//输出结果:0
cout << endl;
//is_abstract判断给定的类型是否是抽象类,如果是返回1,如果不是返回0
cout << std::is_abstract<ETestEnum>::value << endl;//输出结果:0
cout << std::is_abstract<FTestB>::value << endl;//输出结果:0
cout << std::is_abstract<A>::value << endl;//输出结果:0
cout << std::is_abstract<int>::value << endl;//输出结果:0
cout << std::is_abstract<float>::value << endl;//输出结果:0
cout << std::is_abstract<void(int, int)>::value << endl;//输出结果:0
cout << std::is_abstract<void(...)>::value << endl;//输出结果:0
cout << std::is_abstract<float(A::C::*)>::value << endl;//输出结果:0
cout << std::is_abstract<double(A::C::*)()>::value << endl;//输出结果:0
cout << std::is_abstract<vector<int>>::value << endl;//输出结果:0
cout << std::is_abstract<int[]>::value << endl;//输出结果:0
cout << std::is_abstract<FInterface>::value << endl;//输出结果:1
cout << endl;
return 0;
}
is_same
判断类型相同与否
学习.cpp
#include <iostream>
using namespace std;
#include <type_traits>
int main()
{
cout << std::is_same<int, int>::value << endl;//输出结果:1
cout << std::is_same<int&, int>::value << endl;//输出结果:0
cout << std::is_same<int&, std::add_lvalue_reference<int>::type>::value << endl;//输出结果:1
//为type添加了一个引用
//add_lvalue_reference添加引用,在type_traits库里可以看到
cout << std::is_same<int, std::remove_const<const int>::type>::value << endl;//输出结果:1
cout << std::is_same<int&&, std::add_rvalue_reference<int>::type>::value << endl;//输出结果:1
cout << std::is_same<const int, std::add_const<int>::type>::value << endl;//输出结果:1
return 0;
}
通过decltype判断实例类型
int a = 10;
double b = 20;
cout << std::is_same<decltype(a), decltype(b)>::value << endl;
conslitional
用于条件选择,根据条件表达式的结果选择不同的类型
源代码
如果第一个位置bool _Test是true走第二个位置 class _Ty1,如果第一个位置不是bool _Test走第三个位置 class _Ty2
template <bool _Test, class _Ty1, class _Ty2>
struct conditional { // Choose _Ty1 if _Test is true, and _Ty2 otherwise
using type = _Ty1;
};
decltype
用于推断表达式的类型。
获取类型
decltype
是 C++11 引入的一个运算符,用于获取表达式的类型,包括变量、函数、表达式等。
decltype
运算符在编译时确定给定表达式的类型,并返回一个与该表达式的类型相同的值,而不执行实际的表达式或计算。它有两种使用方式:
- 用法一:
decltype(expression)
,返回表达式的类型。 - 用法二:
decltype((variable))
,返回变量的引用类型。
示例:
#include <iostream>
int main() {
int x = 5;
decltype(x) y = 10; // y 的类型为 int
decltype((x)) z = y; // z 的类型为 int&(引用类型)
std::cout << "y: " << y << std::endl;
std::cout << "z: " << z << std::endl;
y = 20; // 修改 y 的值
std::cout << "x: " << x << std::endl; // 输出 5,x 的值未改变
std::cout << "z: " << z << std::endl; // 输出 20,z 是对 x 的引用
return 0;
}
decltype
在元编程和泛型编程中非常有用,可以根据变量或表达式的类型进行类型推导,以便进行进一步的编程操作。
conslitional
学习.cpp
#include <iostream>
using namespace std;
#include <type_traits>
int main()
{
//如果第一个位置是true走第二个位置int,如果第一个位置不是true走第三个位置double
//如果第一个位置是true,后面是int类型,如果第一个位置不是true,后面是double类型
std::conditional<true, int, double>::type Hel1 = 100;
std::conditional<true, int, double>::type Hel2 = 100;
std::conditional<(sizeof(int)>sizeof(long double)), int, float>::type A = 100;
cout << typeid(A).name() << endl;//输出结果:float
return 0;
}
decay
移除操作
用于获取给定类型的"衰变"类型,去除引用、cv限定符并将数组类型转换为指针类型
#include <iostream>
using namespace std;
#include <type_traits>
int main()
{
std::decay<int&>::type A1;//int类型,移除了左引用
std::decay<int&&>::type A2;//int类型,移除了右引用
std::decay<const int>::type A3;//int类型,移除了const
std::decay<int[100]>::type A4;//int*,把数组转换成指针
std::decay<int(int)>::type A5;//int(*)(int)函数指针类型,表示指向int类型参数并返回int类型值的函数的指针
return 0;
}
CV限定符
CV限定符是C++中用于限定类型常量性和易变性的修饰符。CV代表了"const"和"volatile"这两个关键字的缩写。
- const关键字用于声明常量,表示一个变量的值在其初始化后不能再被改变。即,const修饰的变量只能读取其值,不能修改它。例如:
const int num = 10;
- volatile关键字用于声明易变性,表示变量的值可能在未经通知的情况下被修改。volatile通常用于具有特殊要求的变量,如硬件寄存器。对volatile变量的读写操作会被编译器认为是可见的,并不会进行优化。例如:
volatile int flag = 0;
CV限定符可以单独使用,也可以一起使用。例如,const volatile int data = 100;
表示data既是一个只读常量,又是易变的。这样的变量在多线程或嵌入式系统开发中很常见,以实现对共享资源的安全访问。
enable_if
判断是不是整型和浮点型,整形返回true,浮点型(float、double)返回false,不可以添加其他类型,会报错
但是可以解决不能添加其他类型问题,如下代码,加一个新模板,添加一个!,在判断不是整型和浮点型时走新模板
用于在模板中根据某个条件选择是否启用特定函数模板
#include <iostream>
using namespace std;
#include <type_traits>
template<class T>
typename std::enable_if<std::is_arithmetic<T>::value, T>::type Func(T f)
{
return f;
}
class A
{
public:
A() {}
};
//修改版本,可以放自定义类(加了一个!,使不符合上面模板的走此)
template<class T>
typename std::enable_if<!std::is_arithmetic<T>::value, T>::type Func(T f)
{
cout << "F" << endl;
return f;
}
int main()
{
A a;
auto a1 = Func(1);//返回一个类型
auto a2 = Func(1.1f);//正常版只能放整型和浮点型,下面是正常版放自定义类会报错
//auto a3 = Func(a);//会报错
auto a4 = Func(a);
return 0;
}
integral_constant
定义预编译器常量
用于表示编译时常量的类型,可以用于编译时条件判断
#include <iostream>
using namespace std;
#include <type_traits>
int main()
{
//定义预编译器常量,不再需要枚举,使用typedef
typedef std::integral_constant<int, 100>::type Hello;
Hello o;//它的类型是上面定义的Hello,所以o的值为100
int i1 = o;//发生隐式类型转换
int i2 = static_cast<int>(o);//将对象o转换为整数类型,并将转换结果赋值给整数变量i2
int i3 = o.operator Hello::value_type();
cout << i1 << endl;
cout << i2 << endl;
cout << i3 << endl;
return 0;
}
求最大整数
class.h
#pragma once
template<int a,int...Args>
struct IntMax;
template<int a>
struct IntMax<a>:std::integral_constant<int,a>
{
};
template<int a1,int a2, int...Args>
struct IntMax<a1, a2, Args...> :std::integral_constant<int, a1 >= a2 ? IntMax<a1, Args...>::value : IntMax<a2, Args...>::value>
{
};
学习.cpp
#include <iostream>
using namespace std;
#include <type_traits>
#include"class.h"
int main()
{
//比任意算法都快
cout << IntMax<1, 2, 300, 4, 5, 6, 7, 8, 9, 100>::value << endl;//输出结果:300
return 0;
}
求内存对齐
内存对齐可以理解为给数据在计算机内存中找一个合适的位置,使得处理器能够高效地读取或写入这些数据。
想象一下,如果把数据放在内存中的一个奇怪的位置,可能不是以合适的方式存储,处理器在读取或写入这些数据时可能需要多次操作。这会浪费时间和资源,并且可能导致程序变慢。
所以内存对齐就是为了调整数据的存放位置,让数据的起始地址满足一定的规则。这个规则通常是数据类型的大小的整数倍。这样,处理器可以直接从内存中读取或写入整个数据,而不需要进行额外的操作。
通过合理地进行内存对齐,可以提高程序的运行效率,让程序更快速地处理数据。就好比工人在工作时,把工具整整齐齐地放在合适的位置,可以更方便地使用工具,提高工作效率。
如对比int、double、float、long double等,因为不同类型,不同类型的变量按照合理的规则放置在内存中
class.h
#pragma once
template<int a,int...Args>
struct IntMax;
template<int a>
struct IntMax<a>:std::integral_constant<int,a>
{
};
template<int a1,int a2, int...Args>
struct IntMax<a1, a2, Args...> :std::integral_constant<int, a1 >= a2 ? IntMax<a1, Args...>::value : IntMax<a2, Args...>::value>
{
};
template<class ...Args>
struct MaxAlign :std::integral_constant<int, IntMax < std::alignment_of<Args>::value...>::value>
{
};
学习.cpp
#include <iostream>
using namespace std;
#include <type_traits>
#include"class.h"
int main()
{
//比任意算法都快
cout << IntMax<1, 2, 300, 4, 5, 6, 7, 8, 9, 100>::value << endl;//输出结果:300
struct FA
{
int a;
int b;
double a1;
float a2;
long double a3;
};
int A = alignof(FA);
cout << A << endl;//输出结果:8(所以上面对齐方式是按8来的)
cout << MaxAlign<char, int, float, long, long long>::value << endl;//输出结果:8//按内存最大的对齐
return 0;
}
alignment_of
获取指定类型的对齐方式