c++ - 如何删除可变参数模板的最后一个参数

标签 c++ c++11 variadic-templates

我有以下结构,我想从 index_sequence 中删除最后一个参数:

template< std::size_t ... values>
struct index_sequence{};

// I need something like
template< typename IndexSequence>
struct pop_back;

template< std::size_t ... values >
struct pop_back< index_sequence< values... > >
{
    typedef index_sequence< /** values except last one*/ > type;
};

如何实现这个pop_back结构?


我知道实现,只是它需要深度递归,我想要没有深度递归实例化。

我的实现:

template< std::size_t i, typename IndexSequence >
struct insert_head;

template< std::size_t i, std::size_t ...values>
struct insert_head< i, index_sequence<values...> >
{
   typedef index_sequence< i, values... > type;
};

template< > 
struct pop_back< index_sequence<> > 
{ 
typedef index_sequence<> type; // no element will removed 
}; 

template< std::size i > struct pop_back< index_sequence< i > >
{
   typedef index_sequence<> type; // i - will removed
};

template< std::size_t i, std::size_t ...values> 
struct pop_back< index_sequence<i,values...>>
{
    typedef typename pop_back< index_sequence<values...> >::type tail;
    typedef typename insert_head< i, tail>::type type;
};

Edit2:另一个有用的算法,选择第 i 个元素!!!

template< std::size ...i> struct index_sequence;

template< std::size_t index, typename IndexSeq> struct at;

template< std::size_t index, std::size_t ... values> 
struct at< index, index_sequence<values...> >
{
     static constexpr std::size_t get_value()noexcept
     {
          using list = std::size_t [];
          return list{ values...}[index];
     }

    static constexpr std::size_t value = get_value();
}

// test
//                  -- 0 1 2 3 4
typedef index_sequence<2,4,6,8,10>  even_t;

static_assert( at<2, even_t>::value == 6, "!");

最佳答案

同样,使用 Xeo's O(logN) instantiation depth version of gen_seq , 稍作修改:

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

现在,通过友元函数和 ADL 使用我以前的技巧之一:

#include <tuple>
#include <type_traits>

template<class T, std::size_t I>
struct type_index_pair
{
    friend T my_declval(type_index_pair,
                        std::integral_constant<std::size_t, I>);
};

template<class, class>
struct pop_back_helper;

template<class... TT, std::size_t... Is>
struct pop_back_helper<std::tuple<TT...>, seq<Is...>>
{
    struct base : type_index_pair<TT, Is>...
    {};

    template<std::size_t... Is2>
    using join = std::tuple< decltype(my_declval(base{},
                             std::integral_constant<std::size_t, Is2>{}))... >;
};

template<class... TT, std::size_t... Is, std::size_t... Is2>
auto deduce(seq<Is...>, seq<Is2...>)
-> typename pop_back_helper<std::tuple<TT...>, seq<Is...>>
   ::template join<Is2...>
{  return {};  } // definition not required, actually

template<class... TT>
using pop_back = decltype(deduce<TT...>(gen_seq<sizeof...(TT)>{},
                                        gen_seq<sizeof...(TT)-1>{}));

使用示例:

#include <iostream>
template<class T>
void pretty_print(T)
{
    std::cout << __PRETTY_FUNCTION__ << std::endl;
}

int main()
{
    pretty_print( pop_back<int, bool, char, double>{} );
    pretty_print( pop_back<double, int, int>{} );
}

我对它不是特别满意,因为它需要两个 序列加上 ADL(这需要资源而且很慢,AFAIK)。也许我能在接下来的几天里想出更好的办法。

关于c++ - 如何删除可变参数模板的最后一个参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20035374/

相关文章:

C++11 Chrono - 如何将 'unsigned int' 转换为 time_point<system_clock>?

c++ - 依赖于模板参数的成员函数实现

c++ - 使用 C++11 initializer_list 实现类 std::array 容器

c++ - 是否可以使用 static_cast 避免 vtable 开销?

c++ - FFmpeg:使用自定义线程池进行并行编码

python - 从 Python 调用 cpp 函数时出现段错误

c++11 - 未解析的 std::__cxx11::basic_string::~basic_string 和 std::allocator<char>::~allocator() 符号

android - NDK 构建错误

c++ - 这是在调用函数中重用 C++11 lambda 的合理模式吗?

c++ - 这个结构继承的类型是什么?