Tho*_*mas 23 c++ variadic-templates c++11
如何将可变参数模板参数分成两半?就像是:
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...}) {}
};
Run Code Online (Sandbox Code Playgroud)
Tho*_*tit 11
Luc的解决方案干净简洁,但却非常缺乏乐趣.
因为只有一种正确的方法可以使用可变参数模板而且它是滥用它们做疯狂的复杂元编程的东西:)
像这样 :
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;
}
Run Code Online (Sandbox Code Playgroud)
它很短,除了我们需要编写一些帮助:
首先,我们需要结构make_pack_indices,它用于在编译时生成一个整数范围.例如make_pack_indices<5, 0>::type实际上是类型pack_indices<0, 1, 2, 3, 4>
template <size_t...>
struct pack_indices {};
template <size_t Sp, class IntPack, size_t Ep>
struct make_indices_imp;
template <size_t Sp, size_t ... Indices, size_t Ep>
struct make_indices_imp<Sp, pack_indices<Indices...>, Ep>
{
typedef typename make_indices_imp<Sp+1, pack_indices<Indices..., Sp>, Ep>::type type;
};
template <size_t Ep, size_t ... Indices>
struct make_indices_imp<Ep, pack_indices<Indices...>, Ep>
{
typedef pack_indices<Indices...> type;
};
template <size_t Ep, size_t Sp = 0>
struct make_pack_indices
{
static_assert(Sp <= Ep, "__make_tuple_indices input error");
typedef typename make_indices_imp<Sp, pack_indices<>, Ep>::type type;
};
Run Code Online (Sandbox Code Playgroud)
我们还需要一个get()函数,非常类似于std :: get for tuple,比如std::get<N>(ts...)返回参数包的第N个元素.
template <class R, size_t Ip, size_t Ij, class... Tp>
struct Get_impl
{
static R& dispatch(Tp...);
};
template<class R, size_t Ip, size_t Jp, class Head, class... Tp>
struct Get_impl<R, Ip, Jp, Head, Tp...>
{
static R& dispatch(Head& h, Tp&... tps)
{
return Get_impl<R, Ip, Jp + 1, Tp...>::dispatch(tps...);
}
};
template<size_t Ip, class Head, class... Tp>
struct Get_impl<Head, Ip, Ip, Head, Tp...>
{
static Head& dispatch(Head& h, Tp&... tps)
{
return h;
}
};
template <size_t Ip, class ... Tp>
typename pack_element<Ip, Tp...>::type&
get(Tp&... tps)
{
return Get_impl<typename pack_element<Ip, Tp...>::type, Ip, 0, Tp...>::dispatch(tps...);
}
Run Code Online (Sandbox Code Playgroud)
但是为了构建get(),我们还需要一个pack_element辅助结构,再次非常类似于std :: tuple_element,例如pack_element<N, Ts...>::type参数包的第N种类型.
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;
};
Run Code Online (Sandbox Code Playgroud)
现在我们开始.
实际上我真的不明白为什么pack_element和get()不在标准库中.这些助手是为std :: tuple而存在的,为什么不用于参数包呢?
注意:我的pack_element和make_pack_indices实现是libc ++中std :: tuple_element和__make_tuple_indices实现的直接转换.
我们仍然缺乏很多助手来操作可变参数包(或者我不知道它们)。在一个好的 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
}
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,您可以(不那么)轻松地创建自己的算法来操作参数包;所需要的只是对递归和模式匹配的良好理解(与进行模板元编程时一样)。
| 归档时间: |
|
| 查看次数: |
4809 次 |
| 最近记录: |