本来想把scanr,foldr什么的都写了的,一想太麻烦了,就算了,模板元编程差不多也该结束了,离开学还有10天,之前几天部门还要纳新什么的,写不了几天代码了,所以赶紧把这个结束掉,明天继续抄轮子叔的Win32库去。

逻辑结构和递归说白了就是做了一个If,一个For_N,If就和Excel里的If一样,For_N是把一个模板结构迭代N遍,为了所谓的方便,把If做成了宏,写起来还挺有意思的

  1. template<typename TTest, typename TTrue, typename TFalse>
  2. struct If;
  3.  
  4. template<typename TTrue, typename TFalse>
  5. struct If<Bool<true>, TTrue, TFalse>
  6. {
  7. using Result = TTrue;
  8. };
  9.  
  10. template<typename TTrue, typename TFalse>
  11. struct If<Bool<false>, TTrue, TFalse>
  12. {
  13. using Result = TFalse;
  14. };
  15.  
  16. template<typename TTimes, template<typename TResult> typename TProc, typename TDefVal>
  17. struct FOR_N;
  18.  
  19. template<template<typename TResult> typename TProc, typename TDefVal, int VTimes>
  20. struct FOR_N<Int<VTimes>, TProc, TDefVal>
  21. {
  22. using Result = typename TProc<
  23. typename FOR_N<
  24. Int<VTimes - >,
  25. TProc,
  26. TDefVal
  27. >::Result
  28. >::Result;
  29. };
  30.  
  31. template<template<typename TResult> typename TProc, typename TDefVal>
  32. struct FOR_N<Int<>, TProc, TDefVal>
  33. {
  34. using Result = typename TDefVal;
  35. };
  36.  
  37. #if defined SIMPLIFIED_TML
  38.  
  39. #define IF If<
  40. #define THEN ,
  41. #define ELSE ,
  42. #define NOELSE , void
  43. #define NOTHEN , void
  44. #define ENDIF >::Result
  45. #define ELIF ELSE IF
  46.  
  47. #endif

用法就不给了,不会写单元测试

然后是列表的又一部分零碎的东西,Filter就是按照给定的一元谓词筛选整个列表,MapNone和FilterNone属于什么也不做/直接返回true的默认操作,ListGeneration是从给定的列表中生成列表,就像haskell的列表推导式一样,说白了就是Filter一下再Map一下,组合起来挺有意思的,Range就是给定一个类型和上下界,生成一个连续的区间,这里突然想到还可以自定义步长,懒得改了就这样。

  1. template<template<typename TArg> typename TFilter, typename T>
  2. struct ListFilter;
  3.  
  4. template<template<typename TArg> typename TFilter, typename... TArgs>
  5. struct ListFilter<TFilter, List<TArgs...>>
  6. {
  7. using Param = List<TArgs...>;
  8. using Result = typename ListConnect<
  9. typename If<
  10. typename TFilter<typename Param::First>::Result,
  11. List<typename Param::First>,
  12. List<>
  13. >::Result,
  14. typename ListFilter<
  15. TFilter,
  16. typename Param::Rest
  17. >::Result
  18. >::Result;
  19. };
  20.  
  21. template<template<typename TArg> typename TFilter, typename TLast>
  22. struct ListFilter<TFilter, List<TLast>>
  23. {
  24. using Param = List<TLast>;
  25. using Result = typename If<
  26. typename TFilter<typename Param::First>::Result,
  27. List<typename Param::First>,
  28. List<>
  29. >::Result;
  30. };
  31.  
  32. template<typename T>
  33. struct MapNone
  34. {
  35. using Result = T;
  36. };
  37.  
  38. template<typename T>
  39. struct FilterNone
  40. {
  41. using Result = Bool<true>;
  42. };
  43.  
  44. template<template<typename TVal> typename TProcToVal, template<typename TVal> typename TFilterProc, typename... TSeq>
  45. struct ListGeneration;
  46.  
  47. template<template<typename TVal> typename TProcToVal, template<typename TVal> typename TFilterProc, typename... TSeq>
  48. struct ListGeneration<TProcToVal, TFilterProc, List<TSeq...>>
  49. {
  50. using FilterResult = typename ListFilter<TFilterProc, List<TSeq...>>::Result;
  51. using Result = typename ListMap<TProcToVal, FilterResult>::Result;
  52. };
  53.  
  54. template<typename TType, TType VBegin, TType VEnd, TType VCurr = VBegin>
  55. struct Range
  56. {
  57. using Result = typename ListConnect<
  58. List<PODType<TType, VCurr>>,
  59. typename If<
  60. Bool<VCurr < VEnd>,
  61. typename Range<TType, VBegin, VEnd, VCurr + >::Result,
  62. List<>
  63. >::Result
  64. >::Result;
  65. };

用起来还算很爽

  1. 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的更多相关文章

  1. C++模板元编程 - 2 模仿haskell的列表以及相关操作

    这是昨天和今天写的东西,利用C++的可变模板参数包以及包展开,模式匹配的一些东西做的,感觉用typename...比轮子叔那个List<A,List<B, List<C, D> ...

  2. c++ 模板元编程的一点体会

    趁着国庆长假快速翻了一遍传说中的.大名鼎鼎的 modern c++ design,钛合金狗眼顿时不保,已深深被其中各种模板奇技淫巧伤了身...论语言方面的深度,我看过的 c++ 书里大概只有 insi ...

  3. C++模板元编程(C++ template metaprogramming)

    实验平台:Win7,VS2013 Community,GCC 4.8.3(在线版) 所谓元编程就是编写直接生成或操纵程序的程序,C++ 模板给 C++ 语言提供了元编程的能力,模板使 C++ 编程变得 ...

  4. 现代c++与模板元编程

    最近在重温<c++程序设计新思维>这本经典著作,感慨颇多.由于成书较早,书中很多元编程的例子使用c++98实现的.而如今c++20即将带着concept,Ranges等新特性一同到来,不得 ...

  5. C++ 模板元编程 学习笔记

    https://blog.csdn.net/K346K346/article/details/82748163 https://www.jianshu.com/p/b56d59f77d53 https ...

  6. 现代c++模板元编程:遍历tuple

    tuple是c++11新增的数据结构,通过tuple我们可以方便地把各种不同类型的数据组合在一起.有了这样的数据结构我们就可以轻松模拟多值返回等技巧了. tuple和其他的容器不同,标准库没有提供适用 ...

  7. 读书笔记_Effective_C++_条款四十八:了解模板元编程

    作为模板部分的结束节,本条款谈到了模板元编程,元编程本质上就是将运行期的代价转移到编译期,它利用template编译生成C++源码,举下面阶乘例子: template <int N> st ...

  8. effective c++ Item 48 了解模板元编程

    1. TMP是什么? 模板元编程(template metaprogramming TMP)是实现基于模板的C++程序的过程,它能够在编译期执行.你可以想一想:一个模板元程序是用C++实现的并且可以在 ...

  9. 读书笔记 effective c++ Item 48 了解模板元编程

    1. TMP是什么? 模板元编程(template metaprogramming TMP)是实现基于模板的C++程序的过程,它能够在编译期执行.你可以想一想:一个模板元程序是用C++实现的并且可以在 ...

随机推荐

  1. java枚举实例

    实例一: public enum OrderOption {ASC,DESC; } 实例二(带参数构造函数): public enum OrderOption { ASC("ASC" ...

  2. 拉动滚动条追加内容,无限延伸document高度 $(window).scroll(function(){if($(window).scrollTop() + $(window).height() == $(document).height()) { $("body").append(html) } })

    $(document).ready(function() { // endless scrolling $(window).scroll(function() { if($(window).scrol ...

  3. Unicode基本概念

    Unicode是计算机可以支持这个星球上多种语言的秘密武器.通过使用一个或者多个字节来表示一个字符的方法突破了ASCII的限制.Unicode可以表示超过90000个字符. 使用方式:a=u'hell ...

  4. linux包之iproute之ss命令

    概述 [root@localhost ~]# rpm -qa|grep iprouteiproute-2.6.32-31.el6.x86_64 当服务器的socket连接数量变得非常大时,无论是使用n ...

  5. OpenJudge就算概论-统计字符数

    /*===================================== 统计字符数 总时间限制: 1000ms 内存限制: 65536kB 描述 判断一个由a-z这26个字符组成的字符串中哪个 ...

  6. 【转】PHP中require和include路径问题总结

    1 绝对路径.相对路径和未确定路径 2. 相对路径: 3. 绝对路径 4. 未确定路径 5. 解决方案 1 绝对路径.相对路径和未确定路径 相对路径 相对路径指以.开头的路径,例如 ./a/a.php ...

  7. SQLSERVER 复制表--和复制有关的系统表

    主数据库中的复制表 表名 说明 MSreplication_options 表存储供复制在内部使用的元数据. 此表存储在 master 数据库中. msdb 数据库中的复制表 表名 说明 MSagen ...

  8. ORA-27086: unable to lock file - already in use

    问题现象: SQL> startup ORACLE instance started. Total System Global Area 1854021632 bytes Fixed Size  ...

  9. Flex相关案例及资源搜集

    Flex一些例子: http://blog.minidx.com/ 上千个Flex例子,对于学习者来说是一个庞大的资源宝库. http://fleksray.org/Flex_skin.html ht ...

  10. LinkedHashMap和HashMap区别

    import java.util.HashMap; import java.util.Iterator; import java.util.LinkedHashMap; import java.uti ...