inline int fun2(int x) { return x;}inline int fun2(double x) { return 0; }inline int fun2(float x) { return -1; }int fun(const std::tuple<int,double,float>& t,std::size_t i) { switch(i) { case 0: return fun2(std::get<0>(t)); case 1: return fun2(std::get<1>(t)); case 2: return fun2(std::get<2>(t)); } }
问题是我应该如何将其扩展到一般情况
template<class... Args> int fun(const std::tuple<Args...>& t,std::size_t i) {// ?}
保证
> fun2可以嵌入乐趣
>搜索复杂度不逊于O(log(i))(对于大i).
众所周知,当足够大的开关扩展时,优化器通常使用查找跳转表或编译时二叉搜索树.所以,我想保持这个属性影响大量项目的性能.
更新#3:我用均匀随机索引值重新测量了性能:
1 10 20 100@TartanLlama gcc ~0 42.9235 44.7900 46.5233 clang 10.2046 38.7656 40.4316 41.7557@chris-beck gcc ~0 37.564 51.3653 81.552 clang ~0 38.0361 51.6968 83.7704naive tail recursion gcc 3.0798 40.6061 48.6744 118.171 clang 11.5907 40.6197 42.8172 137.066manual switch statement gcc 41.7236 clang 7.3768
更新#2:似乎clang能够在@TartanLlama解决方案中内联函数,而gcc总是生成函数调用.
解决方法 好的,我重写了我的答案.这给了什么TartanLlama和我之前建议的不同的方法.这符合您的复杂性要求,并且不使用函数指针,因此一切都是可以联机的.编辑:非常感谢Yakk指出一个非常显着的优化(对于编译时模板递归深度需要)在注释中
基本上,我使用模板来形成类型/函数处理程序的二叉树,并手动实现二进制搜索.
可能使用mpl或boost :: fusion来更干净地执行此 *** 作,但是这个实现是自包含的.
它绝对符合您的要求,即函数是可以并行的,并且运行时查询在元组中的类型数量是O(log n).
这是完整的列表:
#include <cassert>#include <cstdint>#include <tuple>#include <iostream>using std::size_t;// Basic typeList objecttemplate<typename... TL>struct TypeList{ static const int size = sizeof...(TL);};// Metafunction Concat: Concatenate two typeListstemplate<typename L,typename R>struct Concat;template<typename... TL,typename... TR>struct Concat <TypeList<TL...>,TypeList<TR...>> { typedef TypeList<TL...,TR...> type;};template<typename L,typename R>using Concat_t = typename Concat<L,R>::type;// Metafunction First: Get first type from a typeListtemplate<typename T>struct First;template<typename T,typename... TL>struct First <TypeList<T,TL...>> { typedef T type;};template<typename T>using First_t = typename First<T>::type;// Metafunction Split: Split a typeList at a particular indextemplate<int i,typename TL>struct Split;template<int k,typename... TL>struct Split<k,TypeList<TL...>> {private: typedef Split<k/2,TypeList<TL...>> FirstSplit; typedef Split<k-k/2,typename FirstSplit::R> SecondSplit;public: typedef Concat_t<typename FirstSplit::L,typename SecondSplit::L> L; typedef typename SecondSplit::R R;};template<typename T,typename... TL>struct Split<0,TypeList<T,TL...>> { typedef TypeList<> L; typedef TypeList<T,TL...> R;};template<typename T,typename... TL>struct Split<1,TL...>> { typedef TypeList<T> L; typedef TypeList<TL...> R;};template<int k>struct Split<k,TypeList<>> { typedef TypeList<> L; typedef TypeList<> R;};// Metafunction SubdivIDe: Split a typeList into two roughly equal typeListstemplate<typename TL>struct SubdivIDe : Split<TL::size / 2,TL> {};// Metafunction MakeTree: Make a tree from a typeListtemplate<typename T>struct MakeTree;/*template<>struct MakeTree<TypeList<>> { typedef TypeList<> L; typedef TypeList<> R; static const int size = 0;};*/template<typename T>struct MakeTree<TypeList<T>> { typedef TypeList<> L; typedef TypeList<T> R; static const int size = R::size;};template<typename T1,typename T2,typename... TL>struct MakeTree<TypeList<T1,T2,TL...>> {private: typedef TypeList<T1,TL...> MyList; typedef SubdivIDe<MyList> MySubdivIDe;public: typedef MakeTree<typename MySubdivIDe::L> L; typedef MakeTree<typename MySubdivIDe::R> R; static const int size = L::size + R::size;};// Typehandler: What our Lists will be made oftemplate<typename T>struct type_handler_helper { typedef int result_type; typedef T input_type; typedef result_type (*func_ptr_type)(const input_type &);};template<typename T,typename type_handler_helper<T>::func_ptr_type me>struct type_handler { typedef type_handler_helper<T> base; typedef typename base::func_ptr_type func_ptr_type; typedef typename base::result_type result_type; typedef typename base::input_type input_type; static constexpr func_ptr_type my_func = me; static result_type apply(const input_type & t) { return me(t); }};// Binary search implementationtemplate <typename T,bool b = (T::L::size != 0)>struct apply_helper;template <typename T>struct apply_helper<T,false> { template<typename V> static int apply(const V & v,size_t index) { assert(index == 0); return First_t<typename T::R>::apply(v); }};template <typename T>struct apply_helper<T,true> { template<typename V> static int apply(const V & v,size_t index) { if( index >= T::L::size ) { return apply_helper<typename T::R>::apply(v,index - T::L::size); } else { return apply_helper<typename T::L>::apply(v,index); } }};// Original functionsinline int fun2(int x) { return x;}inline int fun2(double x) { return 0; }inline int fun2(float x) { return -1; }// Adapted functionstypedef std::tuple<int,float> tup;inline int g0(const tup & t) { return fun2(std::get<0>(t)); }inline int g1(const tup & t) { return fun2(std::get<1>(t)); }inline int g2(const tup & t) { return fun2(std::get<2>(t)); }// Registrytypedef TypeList< type_handler<tup,&g0>,type_handler<tup,&g1>,&g2>> registry;typedef MakeTree<registry> jump_table;int apply(const tup & t,size_t index) { return apply_helper<jump_table>::apply(t,index);}// Demoint main() { { tup t{5,1.5,15.5f}; std::cout << apply(t,0) << std::endl; std::cout << apply(t,1) << std::endl; std::cout << apply(t,2) << std::endl; } { tup t{10,2) << std::endl; } { tup t{15,2) << std::endl; } { tup t{20,2) << std::endl; }}
住在Coliru:
http://coliru.stacked-crooked.com/a/3cfbd4d9ebd3bb3a
以上是内存溢出为你收集整理的c – 切换语句可变模板扩展全部内容,希望文章能够帮你解决c – 切换语句可变模板扩展所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)