我的功能设计是通过运行时指定的索引来访问std :: tuple元素
template<std::size_t _Index = 0,typename _Tuple,typename _Function> inline typename std::enable_if<_Index == std::tuple_size<_Tuple>::value,void>::type for_each(_Tuple &,_Function) {} template<std::size_t _Index = 0,typename _Function> inline typename std::enable_if < _Index < std::tuple_size<_Tuple>::value,void>::type for_each(_Tuple &t,_Function f) { f(std::get<_Index>(t)); for_each<_Index + 1,_Tuple,_Function>(t,f); } namespace detail { namespace at { template < typename _Function > struct helper { inline helper(size_t index_,_Function f_) : index(index_),f(f_),count(0) {} template < typename _Arg > void operator()(_Arg &arg_) const { if(index == count++) f(arg_); } const size_t index; mutable size_t count; _Function f; }; }} // end of namespace detail template < typename _Tuple,typename _Function > void at(_Tuple &t,size_t index_,_Function f) { if(std::tuple_size<_Tuple> ::value <= index_) throw std::out_of_range(""); for_each(t,detail::at::helper<_Function>(index_,f)); }
它具有线性复杂性.我怎么能得到O(1)的复杂性?
解决方法
假设您传递类似于通用lambda的东西,即具有重载函数调用运算符的函数对象:
#include <iostream> struct Func { template<class T> void operator()(T p) { std::cout << __PRETTY_FUNCTION__ << " : " << p << "\n"; } };
您可以构建一个函数指针数组:
#include <tuple> template<int... Is> struct seq {}; template<int N,int... Is> struct gen_seq : gen_seq<N-1,N-1,Is...> {}; template<int... Is> struct gen_seq<0,Is...> : seq<Is...> {}; template<int N,class T,class F> void apply_one(T& p,F func) { func( std::get<N>(p) ); } template<class T,class F,int... Is> void apply(T& p,int index,F func,seq<Is...>) { using FT = void(T&,F); static constexpr FT* arr[] = { &apply_one<Is,T,F>... }; arr[index](p,func); } template<class T,class F> void apply(T& p,F func) { apply(p,index,func,gen_seq<std::tuple_size<T>::value>{}); }
用法示例:
int main() { std::tuple<int,double,char,double> t{1,2.3,4,5.6}; for(int i = 0; i < 4; ++i) apply(t,i,Func{}); }
clang也接受一个应用于包含lambda表达式的模式的扩展:
static FT* arr[] = { [](T& p,F func){ func(std::get<Is>(p)); }... };
(虽然我不得不承认这看起来很奇怪)
g 4.8.1拒绝这一点.