C++ 分裂变量模板参数

C++ 分裂变量模板参数,c++,c++11,variadic-templates,C++,C++11,Variadic Templates,如何将可变模板参数分成两半?比如: template <int d> struct a { std::array <int, d> p, q; template <typename ... T> a (T ... t) : p ({half of t...}), q ({other half of t...}) {} }; 模板结构a{ std::数组p,q; 模板a(T…T):p({T…的一半}),q({T…的另一半}){ }; 我们仍然缺少很多

如何将可变模板参数分成两半?比如:

template <int d> struct a {
  std::array <int, d> p, q;
  template <typename ... T> a (T ... t) : p ({half of t...}), q ({other half of t...}) {} 
};
模板结构a{
std::数组p,q;
模板a(T…T):p({T…的一半}),q({T…的另一半}){
};

我们仍然缺少很多助手来操作可变参数包(或者我不知道他们)。在一个好的Boost库将它们带给我们之前,我们仍然可以编写自己的

例如,如果您愿意将数组的初始化推迟到构造函数体,则可以创建并使用一个函数,将部分参数包复制到输出迭代器:

#include <array>
#include <cassert>
#include <iostream>

// Copy n values from the parameter pack to an output iterator
template < typename OutputIterator >
void copy_n( size_t n, OutputIterator )
{
  assert ( n == 0 );
}

template < typename OutputIterator, typename T, typename... Args >
void copy_n( size_t n, OutputIterator out, const T & value, Args... args )
{
  if ( n > 0 )
  {
    *out = value;
    copy_n( n - 1, ++out, args... );
  }
}

// Copy n values from the parameter pack to an output iterator, starting at
// the "beginth" element
template < typename OutputIterator >
void copy_range( size_t begin, size_t size, OutputIterator out )
{
  assert( size == 0 );
}


template < typename OutputIterator, typename T, typename... Args >
void copy_range( size_t begin, size_t size, OutputIterator out, T value, Args... args )
{
  if ( begin == 0 )
  {
    copy_n( size, out, value, args... );
  }
  else
  {
    copy_range( begin - 1, size, out, args... );
  }
}


template < int N > 
struct DoubleArray
{
  std::array< int, N > p;
  std::array< int, N > q;

  template < typename... Args >
  DoubleArray ( Args... args )
  {
    copy_range( 0, N, p.begin(), args... );
    copy_range( N, N, q.begin(), args... );
  } 

};

int main()
{
  DoubleArray<3> mya(1, 2, 3, 4, 5, 6);
  std::cout << mya.p[0] << mya.p[2] << std::endl;  // 13
  std::cout << mya.q[0] << mya.q[2] << std::endl;  // 46
}
#包括
#包括
#包括
//将n个值从参数包复制到输出迭代器
模板
无效副本(大小、输出者)
{
断言(n==0);
}
模板
无效复制(大小、输出计数器输出、常量和值、参数…参数)
{
如果(n>0)
{
*out=值;
复制n(n-1,++out,args…);
}
}
//将n个值从参数包复制到输出迭代器,从
//“beginth”元素
模板
无效复制范围(大小开始、大小、输出计数器输出)
{
断言(大小==0);
}
模板
无效复制范围(大小开始、大小、输出计数器输出、t值、参数…参数)
{
如果(开始==0)
{
复制(大小、输出、值、参数…);
}
其他的
{
复制范围(开始-1、大小、输出、参数…);
}
}
模板
结构双数组
{
std::数组p;
std::数组q;
模板
双数组(Args…Args)
{
复制范围(0,N,p.begin(),args;
复制范围(N,N,q.begin(),args;
} 
};
int main()
{
双阵列mya(1,2,3,4,5,6);

std::coutLuc的解决方案简洁明了,但极度缺乏乐趣。
因为只有一种正确的方法可以使用可变模板,那就是滥用它们来进行疯狂的过度复杂的元编程:)

像这样:

template <class T, size_t... Indx, class... Ts>
std::array<T, sizeof...(Indx)>
split_array_range_imp(pack_indices<Indx...> pi, Ts... ts)
{
    return std::array<T, sizeof...(Indx)>{get<Indx>(ts...)...}; //TADA
}


template <class T, size_t begin, size_t end, class... Ts>
std::array<T, end - begin>
split_array_range(Ts... ts)
{
    typename make_pack_indices<end, begin>::type indices;
    return split_array_range_imp<T>(indices, ts...);
}

template <size_t N>
struct DoubleArray
{
  std::array <int, N> p, q;

  template <typename ... Ts>
  DoubleArray (Ts ... ts) :
  p( split_array_range<int, 0                , sizeof...(Ts) / 2 >(ts...) ),
  q( split_array_range<int, sizeof...(Ts) / 2, sizeof...(Ts)     >(ts...) )
  {
  }
};

int main()
{
    DoubleArray<3> mya{1, 2, 3, 4, 5, 6};
    std::cout << mya.p[0] << "\n" << mya.p[1] << "\n" << mya.p[2] << std::endl;
    std::cout << mya.q[0] << "\n" << mya.q[1] << "\n" << mya.q[2] << std::endl;
}
模板
std::数组
分割数组范围imp(包索引pi,Ts…Ts)
{
返回std::数组{get(ts…)…};//TADA
}
模板
std::数组
分割阵列范围(Ts…Ts)
{
typename make_pack_index::type index;
返回分割数组范围imp(索引,ts…);
}
模板
结构双数组
{
std::数组p,q;
模板
双阵列(Ts…Ts):
p(分割阵列范围(ts…),
q(分割阵列范围(ts…)
{
}
};
int main()
{
双数组mya{1,2,3,4,5,6};

std::cout这里是另一个解决方案:

#include <array>
#include <tuple>
#include <iostream>

template <int i, int o> struct cpyarr_ {
  template < typename T, typename L > static void f (T const& t, L &l) {
    l[i-1] = std::get<i-1+o> (t);
    cpyarr_<i-1,o>::f (t,l);
  }
};

template <int o> struct cpyarr_ <0,o> {
  template < typename T, typename L > static void f (T const&, L&) {}
};

template <int i, int o, typename U, typename ... T> std::array < U, i > cpyarr (U u, T... t) {
  std::tuple < U, T... > l { u, t... };
  std::array < U, i > a; 
  cpyarr_<i,o>::f (l, a); // because std::copy uses call to memmov which is not optimized away (at least with g++ 4.6)
  return a;
}

template <int d> struct a {
  std::array <int, d> p, q;
  template <typename ... T> a (T ... t) : p (cpyarr<d,0> (t...)), q (cpyarr<d,d> (t...)) {} 
};

int main () {
  a <5> x { 0,1,2,3,4,5,6,7,8,9 };
  for (int i = 0; i < 5; i++)
    std::cout << x.p[i] << " " << x.q[i] << "\n";
}
#包括
#包括
#包括
模板结构cpyarr\u{
模板静态空白f(T常量和T,L和L){
l[i-1]=std::get(t);
cpyarr_uf(t,l);
}
};
模板结构cpyarr\u{
模板静态void f(T const&,L&){
};
模板std::数组cpyarr(U,T…T){
std::tuplel{U,T..};
std::数组a;
cpyarr_uf::f(l,a);//因为std::copy使用了对memmov的调用,而这并没有经过优化(至少在g++4.6中是这样)
返回a;
}
模板结构a{
std::数组p,q;
模板a(T…T):p(cpyarr(T…),q(cpyarr(T…){}
};
int main(){
a x{0,1,2,3,4,5,6,7,8,9};
对于(int i=0;i<5;i++)

std::cout我知道这个问题很老了,但我昨天在寻找一个非常类似的问题的解决方案时才发现了它。我自己制定了一个解决方案,最后编写了一个小库,我相信它满足了您的需要。如果您仍然感兴趣,可以找到一个描述。

注意,在这种情况下,您可以使用<代码>标准::初始值设定项列表

template<int... Is> struct index_sequence{};

template<int N, int... Is> struct make_index_sequence
{
    typedef typename make_index_sequence<N - 1, N - 1, Is...>::type type;
};

template<int... Is> struct make_index_sequence<0, Is...>
{
    typedef index_sequence<Is...> type;
};

template <int d> struct a {
    std::array <int, d> p, q;

    constexpr a (const std::initializer_list<int>& t) :
        a(t, typename make_index_sequence<d>::type())
    {}

private:
    template <int... Is>
    constexpr a(const std::initializer_list<int>& t, index_sequence<Is...>) :
        p ({{(*(t.begin() + Is))...}}),
        q ({{(*(t.begin() + d + Is))...}})
    {}
};
模板结构索引_序列{};
模板结构生成索引序列
{
typedef typename make_index_sequence::type type;
};
模板结构生成索引序列
{
类型定义索引_序列类型;
};
模板结构a{
std::数组p,q;
常量表达式a(常量标准::初始值设定项列表和t):
a(t,类型名make_index_sequence::type())
{}
私人:
模板
constexpr a(const std::初始值设定项\u列表&t,索引\u序列):
p({{(*(t.begin()+Is))…}),
q({{(*(t.begin()+d+Is))…})
{}
};

一个有趣的问题。我想,既然您可能可以将arg拆分为元组,那么可以这样开始:。遗憾的是,构造函数的多个参数包是非法的,即使在这种情况下,应该清楚这两个包中的类型。这样的boost库已经存在:boost.fusion。如果有人转换arguboost.fusion可以简单地用来将
元组拆分为两个独立的
元组或
boost::fusion::vector
s。我曾编写过一个演示,但目前我手头只有VC++,它缺少可变模板参数。我知道boost.fusion库,但我想一个处理参数包递归性质的库:我们应该能够操作参数包而不首先将其转换为元组,这需要不必要的计算。然而,我给出的代码确实可以通过使用Fusion简化(也许我会发布另一个答案来说明如何做到这一点)使用
初始值设定项\u list
简化代码:我认为这是最干净的解决方案。我看得越多,就越喜欢它。我认为这应该是公认的答案,因为这是正确的方法。在运行时复制元素有同样的效果,但会带来完全可以避免的性能损失。这不是更好吗呃,用常量引用代替引用?在什么情况下使用引用更可取?我用常量引用代替编译了整个过程,效果很好。
template <size_t _Ip, class _Tp>
class pack_element_imp;

template <class ..._Tp>
struct pack_types {};

template <size_t Ip>
class pack_element_imp<Ip, pack_types<> >
{
public:
    static_assert(Ip == 0, "tuple_element index out of range");
    static_assert(Ip != 0, "tuple_element index out of range");
};

template <class Hp, class ...Tp>
class pack_element_imp<0, pack_types<Hp, Tp...> >
{
public:
    typedef Hp type;
};

template <size_t Ip, class Hp, class ...Tp>
class pack_element_imp<Ip, pack_types<Hp, Tp...> >
{
public:
    typedef typename pack_element_imp<Ip-1, pack_types<Tp...> >::type type;
};

template <size_t Ip, class ...Tp>
class pack_element
{
public:
    typedef typename pack_element_imp<Ip, pack_types<Tp...> >::type type;
};
#include <array>
#include <tuple>
#include <iostream>

template <int i, int o> struct cpyarr_ {
  template < typename T, typename L > static void f (T const& t, L &l) {
    l[i-1] = std::get<i-1+o> (t);
    cpyarr_<i-1,o>::f (t,l);
  }
};

template <int o> struct cpyarr_ <0,o> {
  template < typename T, typename L > static void f (T const&, L&) {}
};

template <int i, int o, typename U, typename ... T> std::array < U, i > cpyarr (U u, T... t) {
  std::tuple < U, T... > l { u, t... };
  std::array < U, i > a; 
  cpyarr_<i,o>::f (l, a); // because std::copy uses call to memmov which is not optimized away (at least with g++ 4.6)
  return a;
}

template <int d> struct a {
  std::array <int, d> p, q;
  template <typename ... T> a (T ... t) : p (cpyarr<d,0> (t...)), q (cpyarr<d,d> (t...)) {} 
};

int main () {
  a <5> x { 0,1,2,3,4,5,6,7,8,9 };
  for (int i = 0; i < 5; i++)
    std::cout << x.p[i] << " " << x.q[i] << "\n";
}
template<int... Is> struct index_sequence{};

template<int N, int... Is> struct make_index_sequence
{
    typedef typename make_index_sequence<N - 1, N - 1, Is...>::type type;
};

template<int... Is> struct make_index_sequence<0, Is...>
{
    typedef index_sequence<Is...> type;
};

template <int d> struct a {
    std::array <int, d> p, q;

    constexpr a (const std::initializer_list<int>& t) :
        a(t, typename make_index_sequence<d>::type())
    {}

private:
    template <int... Is>
    constexpr a(const std::initializer_list<int>& t, index_sequence<Is...>) :
        p ({{(*(t.begin() + Is))...}}),
        q ({{(*(t.begin() + d + Is))...}})
    {}
};