为了求解行列式的值,需要数组的全排列,上一篇文章已经实现了一个元编程的容器了,本章基于容器,定义了二维数组容器用以盛放全排列的结果。那么就看一下具体的实现吧。

首先对原来的容器做了一些修改,主要是因为当容器为空时,一些操作的定义得作一些短路操作,否则就无法编译通过(这里就不得不再次吐槽一下C艹元编程了,一个简单的异常判断都要写一大堆代码),这里在一维数组中增加了两元素的互换操作swap。

#include <type_traits>template<int i, int...num_ts>
constexpr bool contain_number_b = contain_number<i, num_ts...>::b;template<int...is>
struct container;template<int...is>
struct protect_cal;template<int N, int top, int...remains>
struct n_cal
{using t_front = typename protect_cal<remains...>::template t_front<N - 1>::template push_front<top>;using t_after = typename protect_cal<remains...>::template t_after< N - 1>;
};template<int...remains>
struct n_cal<0, remains...>
{using t_front = container<>;using t_after = container<remains...>;
};
/* 屏蔽空参数情况时的类型定义 */
template<int...is>
struct protect_cal
{template<int N>using t_front = typename n_cal<N, is...>::t_front;template<int N>using t_after = typename n_cal<N, is...>::t_after;
};template<>
struct protect_cal<>
{template<int N>using t_front = container<>;template<int N>using t_after = container<>;
};template<int...is>
struct container
{template<int N, int itr, int topop, int... remains>static constexpr int get_cal = get_cal<N, itr + 1, remains...>;template<int N, int ret, int...remains>static constexpr int get_cal<N, N, ret, remains...> = ret;template<int N>static constexpr int get = get_cal<N, 0, is...>;static constexpr int size = sizeof...(is);template<int i> using push_back = container<is..., i>;template<int i> using push_front = container<i, is...>;template<int total_N, int cur_N, typename other>struct st_push_other_back{using t_next = push_back < other::template get<cur_N>>;using ret = typename t_next::template st_push_other_back<total_N, cur_N + 1, other>::ret;};template<int N, typename other>struct st_push_other_back<N, N, other>{using ret = std::conditional_t<N!=0, container<is...>, container<is...> >;};template<typename other>using push_other_back = typename st_push_other_back<other::size, 0, other>::ret;template<int N>using front_n = typename protect_cal<is...>::template t_front<N>;template<int N>using after_n = typename protect_cal<is...>::template t_after<N>;;template<int N, int M>using mid_nm = typename front_n<M>::template after_n<N>;template<int N, int M>struct swap_cal{using swap_front = front_n<N>;using swap_mid = mid_nm<N + 1, M>;using swap_after = after_n<M + 1>;using ret = typename swap_front::template push_back<get<M>>::template push_other_back<swap_mid>::template push_back<get<N>>::template push_other_back<swap_after>;};template<int N, int M>using swap = typename swap_cal<N, M>::ret;template<int N, int v>struct set_cal{using swap_front = front_n<N>;using swap_after = after_n<N + 1>;using ret = typename swap_front::template push_back<v>::template push_other_back<swap_after>;};template<int N, int v>using set = typename set_cal<N, v>::ret;};

接下来实现一下二维的数组:

template<typename...ts>
struct container2d
{template<int N, int itr, typename topop = std::enable_if_t<0==sizeof...(ts), container<> >, typename... remains>struct get_cal{using t = std::conditional_t<0!= sizeof...(ts), typename get_cal<N, itr + 1, remains...>::t, container<> >;};template<int N, typename ret, typename...remains>struct get_cal<N, N, ret, remains...>{using t = ret;};template<int N>using get = std::conditional_t<0!=sizeof...(ts), typename get_cal<N, 0, ts...>::t, void>;static constexpr int size = sizeof...(ts);template<typename t> using push_back = container2d<ts..., t>;template<typename test_t, typename cur_t, typename...remains>static constexpr bool contain_cal = std::is_same_v< test_t, cur_t> || contain_cal<test_t, remains...>;template<typename test_t, typename cur_t>static constexpr bool contain_cal<test_t, cur_t> = std::is_same_v< test_t, cur_t>;template<typename test_t, typename...params>static constexpr bool contain_p = contain_cal<test_t, params...>;template<typename test_t>static constexpr bool contain_p<test_t> = false;template<typename test_t>static constexpr bool contain = contain_p<test_t, ts...>;
};

然后是求全排列的函数,处理的逻辑是:1、交换容器中的sub_idx和main_idx;2、如果交换后的在二维数组cont2d_t中不存在就加入形成cont2d_t_with_new_swap_added类型;3、继续计算子全排列,排列对象为交换后的容器的main_idx以下的数据(这里理解起来有些困难,说起来也困难,直接看代码理解吧);4、循环减少sub_idx,递归执行all_perm,最终得到的结果要特化一下,在sub_idx和main_idx都是0的情况下得到的就是全排列的结果啦。代码如下:

template<typename cont2d_t, typename cont_t, int sub_idx, int main_idx>
struct all_perm
{using swaped_cont_t = std::conditional_t<sub_idx!=main_idx, typename cont_t::template swap<sub_idx, main_idx>, cont_t>;using cont2d_t_with_new_swap_added = std::conditional_t<cont2d_t::template contain<swaped_cont_t>, cont2d_t, typename cont2d_t::template push_back<swaped_cont_t> >;                                           // 将交换后的两个加进去using sub_perm = all_perm< cont2d_t_with_new_swap_added, swaped_cont_t, main_idx - 1, main_idx - 1 >;using cont2d_with_sub_all_perm = typename sub_perm::ret;      // 将交换过sub_idx和main_idx后的子串全排列再加进队列using ret = typename all_perm< cont2d_with_sub_all_perm, cont_t, sub_idx - 1, main_idx>::ret;
};template<typename cont2d_t, typename cont_t, int main_idx>
struct all_perm<cont2d_t, cont_t, 0, main_idx>
{using swaped_cont_t = typename cont_t::template swap<0, main_idx>;using cont2d_t_with_new_swap_added = std::conditional_t<cont2d_t::template contain<swaped_cont_t>, cont2d_t, typename cont2d_t::template push_back<swaped_cont_t> >;                                           // 将交换后的两个加进去using cont2d_with_sub_all_perm = typename all_perm<cont2d_t_with_new_swap_added, swaped_cont_t, main_idx - 1, main_idx - 1>::ret;   // 将交换过sub_idx和main_idx后的子串全排列再加进队列using ret = cont2d_with_sub_all_perm;                                                                                               // 自己的循环已经执行完成
};template<typename cont2d_t, typename cont_t>
struct all_perm<cont2d_t, cont_t, 0, 0>
{/* 该swap的都已经swap完成了 */using ret = std::conditional_t<cont2d_t::template contain<cont_t>, cont2d_t, typename cont2d_t::template push_back<cont_t> >;                                         // 将交换后的两个加进去
};template<typename cont_t>
using all_perm_t = typename all_perm<container2d<>, cont_t, cont_t::size - 1, cont_t::size - 1>::ret;

之前也写过形成一个顺序一维元编程数组的例子,这里贴在下面:

template<int N, int cur_i, int... is>
struct gen_seq
{using t = typename gen_seq<N, 1 + cur_i, is..., cur_i>::t;
};template<int N, int... is>
struct gen_seq<N, N, is...>
{using t = container<is...>;
};template<int N>
using gen_seq_t = typename gen_seq<N, 0>::t;

至此,所有的试验条件都已经具备,就进行一下试验吧。试验代码如下:

#include <conio.h>int main(int argc, char** argv)
{all_perm_t<gen_seq_t<5>> k1;int size_k = decltype(k1)::size;_getch();return 0;
}

可以在_getch调用处打断点,可以看到k1的类型是0-5数组的全排列。接下来结合之前的元编程矩阵运算就可以形成元编程的行列式求和啦。然后就是矩阵求逆以及元编程的BP神经网络实现。

C++元编程实现数组全排列相关推荐

  1. JavaScript—ES6 元编程(5)

    几年前 ES6 刚出来的时候接触过 元编程(Metaprogramming)的概念,不过当时还没有深究.在应用和学习中不断接触到这概念,比如 mobx 5 中就用到了 Proxy 重写了 Observ ...

  2. 【Groovy】编译时元编程 ( 编译时方法注入 | 使用 buildFromSpec、buildFromString、buildFromCode 进行方法注入 )

    文章目录 一.在 MyASTTransformation#visit 方法中进行方法注入 1.使用 new AstBuilder().buildFromSpec 进行方法注入 2.使用 new Ast ...

  3. 【Groovy】编译时元编程 ( 编译时方法拦截 | 在 MyASTTransformation#visit 方法中进行方法拦截 )

    文章目录 一.在 MyASTTransformation#visit 方法中进行方法拦截 二.完整代码示例及进行编译时处理的编译过程 1.Groovy 脚本 Groovy.groovy 2.ASTTr ...

  4. 【Groovy】编译时元编程 ( ASTTransformation#visit 方法简介 | org.codehaus.groovy.ast.ModuleNode 脚本节点 )

    文章目录 一.ASTTransformation#visit 方法简介 二.org.codehaus.groovy.ast.ModuleNode 脚本节点 一.ASTTransformation#vi ...

  5. 【Groovy】MOP 元对象协议与元编程 ( 方法委托 | 批量方法委托 )

    文章目录 一.批量方法委托 二.完整代码示例 一.批量方法委托 在上一篇博客 [Groovy]MOP 元对象协议与元编程 ( 方法委托 | 正常方法调用 | 方法委托实现 | 代码示例 ) 中 , 将 ...

  6. Javascript元编程创建DOM节点

    在使用javascript创建DOM节点的过程中,难免要使用document.createElement.setAttribute. document.createTextNode等冗长.还有浏览器兼 ...

  7. python元编程之使用动态属性实现定制类--特殊方法__setattr__,__getattribute__篇

    问题:实现一个类,要求行为如同namedtuple:只存在给定名称的属性,不允许动态添加实例属性. 主要知识点在于: __setattr__,__getattr__,getattribute__,__ ...

  8. JavaScript 元编程

    大家好,我是若川.今天给分享一篇来自freecodecamp的好文.我是freecodecamp杭州社区组织者之一,有一群小伙伴一起组织线下分享活动,不过2020年我们杭州社区几乎没有活跃,我也没有什 ...

  9. 第12章 元编程与注解、反射

    第12章 元编程与注解.反射 反射(Reflection)是在运行时获取类的函数(方法).属性.父类.接口.注解元数据.泛型信息等类的内部信息的机制.这些信息我们称之为 RTTI(Run-Time T ...

最新文章

  1. 一次Dubbo拥堵的分析
  2. CVPR 2017 全部及部分论文解读集锦
  3. python上海培训哪里比较好-python培训机构上海哪里好?
  4. 使用Docker,Chef和Amazon OpsWorks进行集群范围的Java / Scala应用程序部署
  5. QNetworkRequest 请求类
  6. VO,BO,PO,DO,DTO的区别
  7. 数据结构之图的遍历:深度优先遍历(DFS)
  8. smallint占用几个字节_面试官问我:Object o = new Object() 占用了多少个字节?
  9. MFC初探 —— 设置软件开机自启
  10. NumberFormat 的使用
  11. MongoDB操作文件
  12. 【黑客工作台特效-----附 效果 + 源代码】
  13. c语言的typedef struct 对应java参数类型,JNA实战系列:02JNA与C语言中的数据类型映射以及复杂结构体传参示例...
  14. 编写jQuery插件的方法
  15. 辅助驾驶功能开发-功能规范篇(02)-车道偏离辅助LDP
  16. Android APT不能自动生成文件
  17. UNICODE汉字数据库
  18. 0.91英寸OLED初始化程序
  19. 黑客攻击常见方法及安全策略制订(转)
  20. 李嘉诚拥有8500亿资产,财富早已超过比尔盖茨,为何要藏富呢?

热门文章

  1. mysql无法执行二进制文件_kail系统64,mysql64,出现-bash: bin/mysqld: 无法执行二进制文...
  2. SPDY 是什么?如何部署 SPDY?
  3. 特斯拉向上,蔚来汽车向前
  4. qt实现窗口背景透明
  5. 到底什么是数据湖?全面解读数据湖的缘起、特征、技术、案例和趋势
  6. 上市企业高管背景研究——男、女性高管数据
  7. YTUOJ-HOMEWORK
  8. Think PHP crud,ThinkPHP教程_PHP框架之ThinkPHP(八)【CRUD與連貫操作】
  9. CapsuleRRT: Relationships-aware Regression Tracking via Capsules
  10. 2022-02-14 influxdb集群coordinator启动及请求处理流程解析