C++ 11 Variadic模板:3..n int分为first,middle,last

Sim*_*ten 3 c++ visual-c++ c++11 c++14

正如标题所说,我有一个Variadic模板,至少可以接受3个参数(int's)

template<int p_first, int p_second, int p_third, int... p_rest>
Run Code Online (Sandbox Code Playgroud)

我需要将它们分成第一个,中间一个最后一个

class MyClass {
    OtherClass<p_first> first;
    // Works obviously

    // std::vector<OtherClass> middle... Doesn't work

    OtherClass<p_last> last;
    // No idea how to do this
}
Run Code Online (Sandbox Code Playgroud)

Visual Studio 2015 C++功能可用


编辑:对不起,我忘了提到关键方面.

谢谢你的帖子.我明白了,测试代码并尽快评论!

Tar*_*ama 7

你可以写一个辅助结构,以获得Nintint包:

template <std::size_t N, int... I>
struct get_n : 
    std::integral_constant<int, 
        std::get<N>(std::array<int,sizeof...(I)> { I... })
    >
{};
Run Code Online (Sandbox Code Playgroud)

然后你可以编写元函数来获得中间和结尾:

template <int... I>
using get_middle = get_n<sizeof...(I)/2 - 1, I...>;

template <int... I>
using get_end = get_n<sizeof...(I) - 1, I...>;
Run Code Online (Sandbox Code Playgroud)

您可以这样使用:

using p_last = get_end<p_third, p_rest...>;
OtherClass<p_last> last;
Run Code Online (Sandbox Code Playgroud)

如果你想要一个OtherClass<N>所有中间元素的元组,这是一个相当简单的解决方案.请参阅Yakk的答案,了解更复杂,更灵活的答案.

template <template <int> class ToBuild, class Seq, int... Args>
struct build_tuple;

template <template <int> class ToBuild, std::size_t... Idx, int... Args>
struct build_tuple<ToBuild, std::index_sequence<Idx...>, Args...> {
    using type = std::tuple<ToBuild<get_n<Idx, Args...>::value>...>;   
};

template<int p_first, int p_second, int p_third, int... p_rest>
struct MyClass {
    MyClass() {
        typename build_tuple<OtherClass,
                            std::make_index_sequence<sizeof...(p_rest) + 1>, 
                            p_second, p_third, p_rest...>::type middle;
    }
}; 
Run Code Online (Sandbox Code Playgroud)


Yak*_*ont 7

首先,样板.我在类型而不是常量中工作,因为使用类型进行元编程要容易得多.

template<class T>struct tag{using type=T;};
template<class Tag>using type_t=typename Tag::type;

template<int I>using int_k=std::integral_constant<int, I>;

template<class...>struct types{using type=types;};

template<template<class...>class Z, class pack>
struct apply;
template<template<class...>class Z, class pack>
using apply_t=type_t<apply<Z,pack>>;
template<template<class...>class Z, class...Ts>
struct apply<Z, types<Ts...>>:tag<Z<Ts...>>{};
Run Code Online (Sandbox Code Playgroud)

现在,一旦我们有一组中间元素,我们就可以应用它们.

template <std::size_t N, class... Ts>
using get_t = type_t< std::tuple_element< N, std::tuple<Ts...> > >;
Run Code Online (Sandbox Code Playgroud)

从类型列表中获取第n个类型.

template <class Is, class pack>
struct get_slice;
template <class Is, class pack>
using get_slice_t=type_t<get_slice<Is,pack>>;
template<std::size_t...Is, class...Ts>
struct get_slice<std::index_sequence<Is...>,types<Ts...>>:
  types< get_t<Is, Ts...>... >{};
Run Code Online (Sandbox Code Playgroud)

这让我们可以拿出一个包,从中获取一个切片.

偏移索引序列:

template<class Is, std::size_t I>
struct offset;
template<class Is, std::size_t I>
using offset_t=type_t<offset<Is,I>>;
template<std::size_t...Is, size_t I>
struct offset<std::index_sequence<Is...>, I>:
  tag<std::index_sequence<(I+Is)...>>
{};
Run Code Online (Sandbox Code Playgroud)

从长度len开始提取中间元素:

template<std::size_t start, std::size_t len, class pack>
struct get_mid:
  get_slice< offset_t< std::make_index_sequence<len>, start >, pack >
{};
template<std::size_t start, std::size_t len, class pack>
using get_mid_t=type_t<get_mid<start,len,pack>>;
Run Code Online (Sandbox Code Playgroud)

现在我们可以将你的元素分成第一个,最后一个,并将其余部分放在一个元组中:

template<int p_first, int p_second, int p_third, int...is>
class MyClass {
  using pack = types< int_k<p_first>, int_k<p_second>, int_k<p_third>, int_k<is>... >;
  OtherClass<p_first> first;

  using mid = get_mid_t<1, sizeof...(is)+1, pack >;

  template<class...Ts>
  using OtherClass_tuple = std::tuple<OtherClass<Ts::value>...>;

  apply_t< OtherClass_tuple, mid > middle;

  OtherClass<get_t<sizeof...(is)+2, pack>::value> last;
};
Run Code Online (Sandbox Code Playgroud)