有效地选择可变模板的最后一个参数 [英] effective way to select last parameter of variadic template

查看:117
本文介绍了有效地选择可变模板的最后一个参数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我知道如何选择可变参数模板的第一个参数:

I know how to select first parameter of variadic template:

template< class...Args> struct select_first;
template< class A, class ...Args> struct select_first<A,Args...>{  using type = A;};

这很简单。但是,select_last不相似:

It's a very simple. However, select_last is not similar:

template< class ...Args> struct select_last;
template< class A> struct select_last<A> { using type = A; };
template< class A, class Args...> struct select_last<A,Args...>{ 
        using type = typename select_last<Args...>::type;
};

此解决方案需要深度递归模板实例化。
我尝试用以下方法解决这个问题:

This solution needed deep recursive template instantinations. I try to solve this with as:

template< class A, class Args...>
struct select_last< Args ... , A>{  using type = A; }; // but it's not compiled.

Q:存在更有效的方法来选择可变参数模板的最后一个参数?

Q: exist more effective way to selecting last parameter of variadic templates?

推荐答案

与上次一样,O(logN)实例化深度。

Same approach as last time, O(logN) instantiation depth. Using only one overload, so it should consume less resources.

警告:它目前从元组类型中删除引用。

Warning: it currently removes references from the tuple types. Note: Removed the reference from pack::declval. I think it still works in every case.

index trick在O(log(N ))实例化;修改为使用 std :: size_t 而不是无符号

indices trick in O(log(N)) instantiations, by Xeo; modified to use std::size_t instead of unsigned

    #include <cstddef>

    // using aliases for cleaner syntax
    template<class T> using Invoke = typename T::type;

    template<std::size_t...> struct seq{ using type = seq; };

    template<class S1, class S2> struct concat;

    template<std::size_t... I1, std::size_t... I2>
    struct concat<seq<I1...>, seq<I2...>>
      : seq<I1..., (sizeof...(I1)+I2)...>{};

    template<class S1, class S2>
    using Concat = Invoke<concat<S1, S2>>;

    template<std::size_t N> struct gen_seq;
    template<std::size_t N> using GenSeq = Invoke<gen_seq<N>>;

    template<std::size_t N>
    struct gen_seq : Concat<GenSeq<N/2>, GenSeq<N - N/2>>{};

    template<> struct gen_seq<0> : seq<>{};
    template<> struct gen_seq<1> : seq<0>{};






今天,我意识到有一个不同的,可能更快(编译时间)解决方案来获得第n个类型的元组(基本上是 std :: tuple_element 的实现)。即使它是另一个问题的直接解决方案,


Today, I realized there's a different, simpler and probably faster (compilation time) solution to get the nth type of a tuple (basically an implementation of std::tuple_element). Even though it's a direct solution of another question, I'll also post it here for completeness.

namespace detail
{
    template<std::size_t>
    struct Any
    {
        template<class T> Any(T&&) {}
    };

    template<typename T>
    struct wrapper {};

    template<std::size_t... Is>
    struct get_nth_helper
    {
        template<typename T>
        static T deduce(Any<Is>..., wrapper<T>, ...);
    };

    template<std::size_t... Is, typename... Ts>
    auto deduce_seq(seq<Is...>, wrapper<Ts>... pp)
    -> decltype( get_nth_helper<Is...>::deduce(pp...) );
}

#include <tuple>

template<std::size_t n, class Tuple>
struct tuple_element;

template<std::size_t n, class... Ts>
struct tuple_element<n, std::tuple<Ts...>>
{
    using type = decltype( detail::deduce_seq(gen_seq<n>{},
                                              detail::wrapper<Ts>()...) );
};

最后一个元素的帮助器:

Helper for last element:

template<typename Tuple>
struct tuple_last_element;

template<typename... Ts>
struct tuple_last_element<std::tuple<Ts...>>
{
    using type = typename tuple_element<sizeof...(Ts)-1,
                                        std::tuple<Ts...>> :: type;
};

使用示例:

#include <iostream>
#include <type_traits>
int main()
{
    std::tuple<int, bool, char const&> t{42, true, 'c'};

    tuple_last_element<decltype(t)>::type x = 'c'; // it's a reference

    static_assert(std::is_same<decltype(x), char const&>{}, "!");
}






原始版本:


Original version:

#include <tuple>
#include <type_traits>

namespace detail
{
    template<typename Seq, typename... TT>
    struct get_last_helper;

    template<std::size_t... II, typename... TT>
    struct get_last_helper< seq<II...>, TT... >
    {
        template<std::size_t I, std::size_t L, typename T>
        struct pack {};
        template<typename T, std::size_t L>
        struct pack<L, L, T>
        {
            T declval();
        };

        // this needs simplification..
        template<typename... TTpacked>
        struct exp : TTpacked...
        {
            static auto declval_helper()
                -> decltype(std::declval<exp>().declval());
            using type = decltype(declval_helper());
        };

        using type = typename exp<pack<II, sizeof...(TT)-1, TT>...>::type;
    };
}

template< typename Tuple >
struct get_last;

template< typename... TT >
struct get_last<std::tuple<TT...>>
{
    template<std::size_t... II>
    static seq<II...> helper(seq<II...>);
    using seq_t = decltype(helper(gen_seq<sizeof...(TT)>()));

    using type = typename detail::get_last_helper<seq_t, TT...>::type;
};


int main()
{
    using test_type = std::tuple<int, double, bool, char>;

    static_assert(std::is_same<char, get_last<test_type>::type>::value, "!");
    // fails:
    static_assert(std::is_same<int, get_last<test_type>::type>::value, "!");
}

这篇关于有效地选择可变模板的最后一个参数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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