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))...}})
{}
};