C++模板元编程 - 3 逻辑结构,递归,一点列表的零碎,一点SFINAE
本来想把scanr,foldr什么的都写了的,一想太麻烦了,就算了,模板元编程差不多也该结束了,离开学还有10天,之前几天部门还要纳新什么的,写不了几天代码了,所以赶紧把这个结束掉,明天继续抄轮子叔的Win32库去。
逻辑结构和递归说白了就是做了一个If,一个For_N,If就和Excel里的If一样,For_N是把一个模板结构迭代N遍,为了所谓的方便,把If做成了宏,写起来还挺有意思的
template<typename TTest, typename TTrue, typename TFalse>
struct If; template<typename TTrue, typename TFalse>
struct If<Bool<true>, TTrue, TFalse>
{
using Result = TTrue;
}; template<typename TTrue, typename TFalse>
struct If<Bool<false>, TTrue, TFalse>
{
using Result = TFalse;
}; template<typename TTimes, template<typename TResult> typename TProc, typename TDefVal>
struct FOR_N; template<template<typename TResult> typename TProc, typename TDefVal, int VTimes>
struct FOR_N<Int<VTimes>, TProc, TDefVal>
{
using Result = typename TProc<
typename FOR_N<
Int<VTimes - >,
TProc,
TDefVal
>::Result
>::Result;
}; template<template<typename TResult> typename TProc, typename TDefVal>
struct FOR_N<Int<>, TProc, TDefVal>
{
using Result = typename TDefVal;
}; #if defined SIMPLIFIED_TML #define IF If<
#define THEN ,
#define ELSE ,
#define NOELSE , void
#define NOTHEN , void
#define ENDIF >::Result
#define ELIF ELSE IF #endif
用法就不给了,不会写单元测试
然后是列表的又一部分零碎的东西,Filter就是按照给定的一元谓词筛选整个列表,MapNone和FilterNone属于什么也不做/直接返回true的默认操作,ListGeneration是从给定的列表中生成列表,就像haskell的列表推导式一样,说白了就是Filter一下再Map一下,组合起来挺有意思的,Range就是给定一个类型和上下界,生成一个连续的区间,这里突然想到还可以自定义步长,懒得改了就这样。
template<template<typename TArg> typename TFilter, typename T>
struct ListFilter; template<template<typename TArg> typename TFilter, typename... TArgs>
struct ListFilter<TFilter, List<TArgs...>>
{
using Param = List<TArgs...>;
using Result = typename ListConnect<
typename If<
typename TFilter<typename Param::First>::Result,
List<typename Param::First>,
List<>
>::Result,
typename ListFilter<
TFilter,
typename Param::Rest
>::Result
>::Result;
}; template<template<typename TArg> typename TFilter, typename TLast>
struct ListFilter<TFilter, List<TLast>>
{
using Param = List<TLast>;
using Result = typename If<
typename TFilter<typename Param::First>::Result,
List<typename Param::First>,
List<>
>::Result;
}; template<typename T>
struct MapNone
{
using Result = T;
}; template<typename T>
struct FilterNone
{
using Result = Bool<true>;
}; template<template<typename TVal> typename TProcToVal, template<typename TVal> typename TFilterProc, typename... TSeq>
struct ListGeneration; template<template<typename TVal> typename TProcToVal, template<typename TVal> typename TFilterProc, typename... TSeq>
struct ListGeneration<TProcToVal, TFilterProc, List<TSeq...>>
{
using FilterResult = typename ListFilter<TFilterProc, List<TSeq...>>::Result;
using Result = typename ListMap<TProcToVal, FilterResult>::Result;
}; template<typename TType, TType VBegin, TType VEnd, TType VCurr = VBegin>
struct Range
{
using Result = typename ListConnect<
List<PODType<TType, VCurr>>,
typename If<
Bool<VCurr < VEnd>,
typename Range<TType, VBegin, VEnd, VCurr + >::Result,
List<>
>::Result
>::Result;
};
用起来还算很爽
ListGeneration<Mul2, FilterNone, Range<int, , >::Result>::Result list2;
Mul2是一个定义好的操作,就是接受一个类型值,然后把他乘以2,C++模板的递归层数最多不能超过255原来是指整个表达式的递归层数啊,我这里上界最多写到63就不能写下去了。
SFINAE,模板替换失败不是一个错误,在编译器根据模板寻找重载函数的时候,如果一个重载的模板替换失败,那么编译器会去寻找其他的重载,直到最后找不到了再报错,由此可以通过一组函数重载过一个过滤器,根据不同的模板参数执行做不同的返回值,通过返回值来达到类型筛选和查错的目的。
C++17的Concept也是基于SFINAE的,好激动。
只看了type SFINAE,expression的还没看,也不准备看了,感觉没什么卵用,还是过段时间买那本C++模板元编程系统学习一下吧。
这里翻译了一下cppreference.com上的东西:
以下属于SFINAE错误
- 尝试实例化一个包含多个不同长度包的包扩展(没看懂,这是什么意思)
- 尝试创建一个void数组,引用的数组,函数的数组,抽象类的数组,负数或零长度的数组
- 尝试在::运算符左侧使用一个非类或枚举类型
- 尝试使用一个类型的成员,若:尝试创建一个指向引用的指针
- 该类型不包含此成员
- 在需要类型的地方,这个成员不是类型
- 在需要模板的地方,这个成员不是模板类型
- 在需要非类型的地方,这个成员不是非类型
- 尝试创建一个void引用
- 尝试创建一个指向T的成员的指针,但T不是类类型
- 尝试给非类型模板参数一个错误类型的值
- 尝试在以下情形进行一个无效转换:尝试创建一个参数是void类型的函数
- 在模板参数表达式中
- 在函数声明表达式中
- 尝试创建一个返回函数或数组的函数
- 尝试创建一个const volatile修饰的函数
- 尝试创建一个参数或返回值是抽象类的函数
自己也没写什么东西,对这套路子不是很熟,等我把C++那些奇怪的语法和指针声明什么的弄明白了这里也就该差不多了。
C++模板元编程 - 3 逻辑结构,递归,一点列表的零碎,一点SFINAE的更多相关文章
- C++模板元编程 - 2 模仿haskell的列表以及相关操作
这是昨天和今天写的东西,利用C++的可变模板参数包以及包展开,模式匹配的一些东西做的,感觉用typename...比轮子叔那个List<A,List<B, List<C, D> ...
- c++ 模板元编程的一点体会
趁着国庆长假快速翻了一遍传说中的.大名鼎鼎的 modern c++ design,钛合金狗眼顿时不保,已深深被其中各种模板奇技淫巧伤了身...论语言方面的深度,我看过的 c++ 书里大概只有 insi ...
- C++模板元编程(C++ template metaprogramming)
实验平台:Win7,VS2013 Community,GCC 4.8.3(在线版) 所谓元编程就是编写直接生成或操纵程序的程序,C++ 模板给 C++ 语言提供了元编程的能力,模板使 C++ 编程变得 ...
- 现代c++与模板元编程
最近在重温<c++程序设计新思维>这本经典著作,感慨颇多.由于成书较早,书中很多元编程的例子使用c++98实现的.而如今c++20即将带着concept,Ranges等新特性一同到来,不得 ...
- C++ 模板元编程 学习笔记
https://blog.csdn.net/K346K346/article/details/82748163 https://www.jianshu.com/p/b56d59f77d53 https ...
- 现代c++模板元编程:遍历tuple
tuple是c++11新增的数据结构,通过tuple我们可以方便地把各种不同类型的数据组合在一起.有了这样的数据结构我们就可以轻松模拟多值返回等技巧了. tuple和其他的容器不同,标准库没有提供适用 ...
- 读书笔记_Effective_C++_条款四十八:了解模板元编程
作为模板部分的结束节,本条款谈到了模板元编程,元编程本质上就是将运行期的代价转移到编译期,它利用template编译生成C++源码,举下面阶乘例子: template <int N> st ...
- effective c++ Item 48 了解模板元编程
1. TMP是什么? 模板元编程(template metaprogramming TMP)是实现基于模板的C++程序的过程,它能够在编译期执行.你可以想一想:一个模板元程序是用C++实现的并且可以在 ...
- 读书笔记 effective c++ Item 48 了解模板元编程
1. TMP是什么? 模板元编程(template metaprogramming TMP)是实现基于模板的C++程序的过程,它能够在编译期执行.你可以想一想:一个模板元程序是用C++实现的并且可以在 ...
随机推荐
- FreeSWITCH安装报错“You must install libyuv-dev to build mod_fsv”的解决方案
昨天下午安装FreeSWITCH时遇到该问题时,整了一个下午都没解决,也走了许多弯路.如果直接通过yum安装libyuv-devel时,会报错说找不到该安装包.后来又通过FreeSWITCH官网的网上 ...
- div下的img标签中图片的大小设定
首先html为: <div class="box1"><img src="images/more-1.jpg"></div> ...
- Unity3D研究院之Machine动画脚本自动生成AnimatorController(七十一)
以前的项目一直不敢用Machine动画,因为当时立项的时候Machine动画还不成熟,最近项目做得差不多了我能有点时间学习,我就想在研究学习学习Machine.用Machine动画的时候需要创建一个A ...
- 只显示 前100个字 java 实现截取字符串!使用! <c:if test="${fn:length(onebeans.info)>100 }">${ fn:substri
博客 文章 只显示 前100个字 java 实现截取字符串!使用! <c:if test="${fn:length(onebeans.info)>100 }">$ ...
- XML 命名空间(XML Namespaces)
XML 应用程序 XML CDATA XML 命名空间提供避免元素命名冲突的方法. 命名冲突 在 XML 中,元素名称是由开发者定义的,当两个不同的文档使用相同的元素名时,就会发生命名冲突. 这个 X ...
- 关于spring 3.0.5的 <mvc:resources mapping="***" location="***">标签的使用
spring mvc 的<mvc;resources mapping="***" location="***">标签是在spring3.0.4出现的 ...
- 008. asp.net mvc3.0安装文件及其安装时发生错误的解决方案
0. 安装步骤: vs2010 → vs2010sp1→ AspNetMVC3Setup.exe→ AspNetMVC3Setup_CHS.exe→ AspNetMVC3ToolsUpdateSetu ...
- Oracle数据库—— 游标的创建和应用
一.涉及内容 游标的创建与应用 二.具体操作 (一)填空题 1.PL/SQL 程序块主要包含3个部分:声明部分.(执行部分 ).异常处理部分. 2.自定义异常必须使用(RAISE )语句引发. (二) ...
- sqlserver快照,启用基于行版本控制的隔离级别
在sqlserver标准的已提交读(read committed)隔离级别下,读写操作相互阻塞.未提交读(read uncommitted)虽然不会有这种阻塞,但是读操作可能会读到脏数据,这是大部分用 ...
- SQLSERVER 脚本转MYSQL 脚本的方法总结
1.MYSQL(版本为5.6)中SQL脚本必须以分号(;)结尾,这点比SQLSERVER要严谨:关键字与函数名称全部大写:数据库名称.表名称.字段名称全部小写. 2.所有关键字都要加上``,比如 St ...