在运行时通过索引访问std :: tuple元素的最佳方式 [英] Optimal way to access std::tuple element in runtime by index

查看:172
本文介绍了在运行时通过索引访问std :: tuple元素的最佳方式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在功能,用于通过运行时指定的索引访问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)
{}
$ b 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& t,_Function f)
{
f(std :: get< _Index> );
for_each< _Index + 1,_Tuple,_Function>(t,f);
}

命名空间detail {{

模板下的命名空间< typename _Function>
struct helper
{
inline helper(size_t index_,_Function f_):index(index_),f(f_),count(0){}

< typename _Arg>
void operator()(_ Arg& arg_)const
{
if(index == count ++)
f(arg_)
}

const size_t index;
mutable size_t count;
_Function f;
};

}} //命名空间详细信息结束

template< typename _Tuple,typename _Function>
void at(_Tuple& t,size_t index_,_Function f)
{
if(std :: tuple_size< _Tuple> :: value< = index_)
throw std ::超出范围();

for_each(t,detail :: at :: helper< _Function>(index_,f));
}

它具有线性复杂性。假设你传递的东西类似于一个通用的lambda,即一个函数对象与一个通用的lambda,一个重载的函数调用操作符:

  #include< iostream> 

struct Func
{
template< class T>
void operator()(T p)
{
std :: cout< __PRETTY_FUNCTION__<< :<< p < \\\
;
}
};

您可以构建一个函数指针数组:

  #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<
}

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,int index,F func)
{
apply(p,index,func,gen_seq< std :: tuple_size& ;
}

使用示例:

  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拒绝此操作。


I have function at designed to access std::tuple element by index specified in runtime

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 _Tuple, 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));
}

It has linear complexity. How can i achive O(1) complexity?

解决方案

Assuming you pass something similar to a generic lambda, i.e. a function object with an overloaded function call operator:

#include <iostream>

struct Func
{
    template<class T>
    void operator()(T p)
    {
        std::cout << __PRETTY_FUNCTION__ << " : " << p << "\n";
    }
};

The you can build an array of function pointers:

#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, int index, F func)
{
    apply(p, index, func, gen_seq<std::tuple_size<T>::value>{});
}

Usage example:

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++ also accepts an expansion applied to a pattern that contains a lambda expression:

static FT* arr[] = { [](T& p, F func){ func(std::get<Is>(p)); }... };

(although I've to admit that looks really weird)

g++4.8.1 rejects this.

这篇关于在运行时通过索引访问std :: tuple元素的最佳方式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆