Rokiのチラ裏

学生による学習のログ

C++11でタプルを関数の引数へ渡す

C++11の環境ではinteger sequenceが標準搭載されていないので、そういった場合への対処法としてメモ。以下のコードはclang 4.0.0の-std=c++11モードで確認している。

まず単純に再起して、パラメータパックがたまりきった所で呼び出す方法。

inline void foo(){}
template<class T,class... Args>
void foo(T&& head,Args&&... tail)
{
    std::cout<<head<<std::endl;
    return foo(std::forward<Args>(tail)...);
}

template<class... Args>
auto expr(Args&&... args)->void
{
    return foo(std::forward<Args>(args)...);
}

struct call_impl{
    struct call_function{
        template<class _Tp,std::size_t l,class Tuple,class... Args>
        static auto invoke(const std::integral_constant<_Tp,l>&,Tuple&&,Args&&... args)->void
        {
            return expr(std::forward<Args>(args)...);
        }
    };

    struct unpack{
        template<class _Tp,std::size_t l,class Tuple,class... Args>
        static auto invoke(const std::integral_constant<_Tp,l>&,Tuple&& t,Args&&... args)->void
        {
            return apply(std::integral_constant<_Tp,l+1>(),std::forward<Tuple>(t),std::forward<Args>(args)...,std::get<l>(t));   
        }
    };

    template<class _Tp,std::size_t l,class Tuple,class... Args>
    static auto apply(const std::integral_constant<_Tp,l>& intconstant,Tuple&& t,Args&&... arg)->void
    {
        return std::conditional<
            sizeof...(arg)==std::tuple_size<typename std::remove_reference<Tuple>::type>::value,
            call_function,
            unpack
        >::type::invoke(intconstant,std::forward<Tuple>(t),std::forward<Args>(arg)...);
    }
};

template<class Tuple>
auto invoke(Tuple&& t)->void
{
    call_impl::apply(std::integral_constant<std::size_t,0>(),std::forward<Tuple>(t));
}

int main()
{
    std::tuple<int,char,bool,float> t{42,'a',true,4.2f};
    invoke(t);
}

次にinteger sequenceを自作する方法。

template<class T,T... Ts>
struct integer_sequence{
    typedef T value_type;
    static constexpr std::size_t size()noexcept{return sizeof...(Ts);}
};
template<std::size_t... V>
using index_sequence=integer_sequence<std::size_t,V...>;

template<std::size_t,class>
struct make_index_sequence_impl;
template<std::size_t n,std::size_t... l>
struct make_index_sequence_impl<n,index_sequence<l...>>{
    typedef typename make_index_sequence_impl<n-1,index_sequence<n-1,l...>>::type type;
};
template<std::size_t... l>
struct make_index_sequence_impl<0,index_sequence<l...>>{
    typedef index_sequence<l...> type;
};
template<std::size_t n,class T=index_sequence<>>
using make_index_sequence=typename make_index_sequence_impl<n,T>::type;

void hoge(){}
template<class Head,class... Tail>
auto hoge(Head&& head,Tail&&... tail)->void
{
    std::cout<<std::forward<Head>(head)<<std::endl;
    hoge(std::forward<Tail>(tail)...);
}

template<class Tuple,std::size_t... l>
auto invoke_impl(Tuple&& t,index_sequence<l...>)->void
{
    hoge(std::get<l>(t)...);
}

template<class Tuple>
void invoke(Tuple&& t)
{
    invoke_impl(std::forward<Tuple>(t),make_index_sequence<std::tuple_size<Tuple>::value>());
}

int main()
{
    invoke(std::tuple<int,char,bool,float>{42,'a',true,42.0f});
}