用于记录对于template 编译器计算的学习
C++ 的模板处理和实现在编译期进行,理论上说 C++ 模板可以执行任何计算任务,但实际上因为模板是编译期计算, 其能力受到具体编译器实现的限制。
另外 if constexpr 条件判断也发生在编译期
编译器if else 选择
template<bool cond,
typename Then,
typename Else>
struct IF;//原始模板
template<typename Then,
typename Else>
struct IF<true, Then, Else> {
typedef Then result;
};//偏特化模板,用于处理状态cond为true的情况的分支
template<typename Then,
typename Else>
struct IF<false, Then, Else> {
typedef Else result;
};//偏特化模板,用于处理状态cond为false的情况的分支
//Then和Else 通常是std::true,std::false或者其他处理模板
通过使用对于模板的偏特化,实现在编译器进行IF ELSE 的分支选择。
template实现编译期递归
template<int n>
struct factorial {
static_assert(n >= 0, "Arg must be non-negative");
//报错,正常的执行不会在该模板中执行到n==0的情况
static const int value = n * factorial<n - 1>::value;
};
template<>
struct factorial<0> {
static const int value = 1;
};//n==0的特例化情况
使用template实现fmap(一个函数对于一组参数进行处理)
template< //一个定义两个类型的模板,默认的OutContainer是vector,传入的模板为vector
template<typename, typename>
class OutContainer = vector,
typename F, class R> // 函数F和类型R
auto fmap(F &&f, R &&inputs) {
// 因为 F 和 R 均是模板type 因此 F&& 和 R&& 在此处均是万能引用
typedef decay_t<decltype(f(*inputs.begin()))> result_type; //decay_t 使类型退化为原始类型
OutContainer<result_type, allocator<result_type >> result;
//创建存储result_type的容器
for (auto &&item:inputs) {
result.push_back(f(item));
}
return result;//批量计算函数,使一个函数能够对一系列数据进行运算
}
int add_1(int x) {
return x + 1;
}
int main() {
vector<int> v{1, 2, 3, 4, 5};
auto result = fmap(add_1, v);
}
值得注意的是:
std::decay_t的作用是使变量退化,变为其原始类型,如 int & ->int , double * -> double
向模板传入模板的时候可以像以上的形式,template<typename ,typename> class Outcontainer=vector,声明号模板的参数个数然后使用传入的模板进行赋值就可以(正如上述中vector模板传入的参数有两个,一个为类型type、一个为容器分配器Allocator<type> )
综合上述的一些模板编译器计算处理的技巧,可以使用模板实现编译器While循环来进行计算:
利用template实现编译期While循环
//typename 后面的有:: 符号,且后面参数是一个类型 用于说明后面跟随的是一个type
template<bool conditon,typename Body>
struct WhileLoop;
template<typename Body>
struct WhileLoop<true, Body> {
typedef typename WhileLoop< Body::cond_value,typename Body::next_type>::type type;
};
template<typename Body>
struct WhileLoop<false, Body> {
typedef typename Body::res_type type;
};
//以上三个WhileLoop为递归运算,用于对Body中的res_type进行递归求值
template<typename Body>
struct While {
typedef typename WhileLoop< Body::cond_value, Body>::type type;
};
template<typename Body>
using While_t = WhileLoop< Body::cond_value, Body>; // While_t 是WhileLoop 的别名
//While的作用是 调用 实例化Whileloop 形成循环
namespace my {
template<typename T,T v>
struct integral_constant {
static const T value = v; //值
typedef T value_type; //类型名
typedef integral_constant<T, v> type; //自身
};
};// Body的res_type的存储结构,因为是使用 type 的形式进行递归运算,所以应当使用 类模板来进行存储
template<int result,int n>
struct SumLoop {
static const int result_value = result;//当前的值 const是为了在编译期就有值
static const bool cond_value = n !=0;//结束条件
typedef my::integral_constant<int, result_value> res_type;//当前循环的状态
typedef SumLoop<result + n, n - 1> next_type;//下一次循环
};
//SumLoop 是循环主体 Body
template<int n>
struct Sum {
typedef SumLoop<0, n> type;//Sum::type是SumLoop<0,n>的别名
};
template<int n>
using Sum_t = SumLoop<0, n>; //Sum_t是SumLoop<0,n>的别名
// Sum和Sum_t 是SumLoop 的抽象封装
int main(){
cout << While< Sum<6>::type >::type::value<<endl;
cout << While< SumLoop <0, 6> >::type::value << endl;
cout << WhileLoop<SumLoop <0, 6>::cond_value, SumLoop <0, 6>>::type::value << endl;
// 以上三种情况都是相同的模板运算,只是由抽象到具体
//While是WhileLoop的封装,Sum是SumLoop的封装,实质为WhileLoop根据SumLoop的状态cond_value
//来逐步递归得到SumLoop的最后一次next_type的值result_type并重命名为type,最后取type中的value即可
//因为最后得到的 type 是integral_constant的结构体
cout << While_t< Sum_t<6> >::type::value << endl;
// 使用using来代替typedef对于type来进行引用
}
While循环的由内到外的层次
my::itergral_constant -> SumLoop -> Sum -> WhileLoop -> While
单个数据 -> 循环体 -> 循环体封装 -> 递归获取res_type -> 递归封装
typename在typedef 中,且后面参数为 type(类型)参数,且为其他作用域中的成员时,才需要在其前面加typename 即 typedef typename A::B C 这种形式