展开两个参数包

Art*_*zuk 6 c++ c++11

请考虑以下代码:

static constexpr size_t Num {2};
struct S {
    std::array<size_t, Num> get () { return {1, 2}; }
};

struct S1 : S {};
struct S2 : S {};

struct M {
    template <typename T>
    typename std::enable_if<std::is_same<T, S1>::value, S1>::type get () const { 
        return S1 {}; 
    }

    template <typename T>
    typename std::enable_if<std::is_same<T, S2>::value, S2>::type get () const { 
        return S2 {}; 
    }
};
Run Code Online (Sandbox Code Playgroud)

我想要一个合并两个或多个std::arrays 的功能std::array.

到目前为止,我结束了这样的事情:

template <typename Mode, typename... Rs, size_t... Ns>
std::array<size_t, sizeof... (Rs)*Num> get_array (const Mode& mode, Sequence::Sequence<Ns...>) {
    return {std::get<Ns> (mode.template get<Rs...> ().get ())...};
}
Run Code Online (Sandbox Code Playgroud)

我希望得到以下代码

M m;
auto x = get_array<M, S1, S2> (m, Sequence::Make<2> {});
Run Code Online (Sandbox Code Playgroud)

生产std::array<size_t, 4>充满{1, 2, 1, 2}.

在哪里Sequence::SequenceSequence::Make这里描述.

我知道,放置...Rs在这方面是不正确的(如果sizeof... (Rs)是1,那么它是好的,std::array<size_t, 2>{1, 2}返回),但我不知道在哪里把它做扩展,看起来像这样:

std::get<0> (mode.template get<Rs[0]> ().get ()), 
std::get<1> (mode.template get<Rs[0]> ().get ()),
std::get<0> (mode.template get<Rs[1]> ().get ()), 
std::get<1> (mode.template get<Rs[1]> ().get ());
Run Code Online (Sandbox Code Playgroud)

当然Rs[0]我的意思是参数包中的第一个类型.

它甚至可能吗?

Bar*_*rry 2

首先,这基本上是要求连接任意数量的数组。这与连接任意数量的元组非常相似,即使在 C++11 中,也有一个标准库函数:std::tuple_cat()。这让我们差不多到了:

template <class... Ts, class M>
auto get_array(M m) -> decltype(std::tuple_cat(m.template get<Ts>()...)) {
    return std::tuple_cat(m.template get<Ts>()...);
}
Run Code Online (Sandbox Code Playgroud)

请注意,我翻转了模板参数,因此这只是get_array<T1, T2>(m)不必编写get_array<M, T1, T2>(m).

现在的问题是,我们该怎么写呢array_cat?我们只需使用tuple_cat结果并将tuple其转换为array. 假设 的实现index_sequence可用(无论如何,这都是您想要的):

template <class T, class... Ts, size_t... Is>
std::array<T, sizeof...(Ts)+1> to_array_impl(std::tuple<T, Ts...>&& tup,
                                             std::index_sequence<Is...> ) {
    return {{std::get<Is>(std::move(tup))...}};
}

template <class T, class... Ts>
std::array<T, sizeof...(Ts)+1> to_array(std::tuple<T, Ts...>&& tup) {
    return to_array_impl(std::move(tup), std::index_sequence_for<T, Ts...>());
}

template <class... Tuples>
auto array_cat(Tuples&&... tuples) -> decltype(to_array(std::tuple_cat(std::forward<Tuples>(tuples)...))) {
    return to_array(std::tuple_cat(std::forward<Tuples>(tuples)...));
}
Run Code Online (Sandbox Code Playgroud)

这给了你:

template <class... Ts, class M>
auto get_array(M m) -> decltype(array_cat(m.template get<Ts>()...)) {
    return array_cat(m.template get<Ts>()...);
}
Run Code Online (Sandbox Code Playgroud)

它处理任意多种类型。