问题
I want to fill the template parameters passed to a variadic template into an array with fixed length. For that purpose I wrote the following helper function templates
template<typename ForwardIterator, typename T>
void fill(ForwardIterator i) { }
template<typename ForwardIterator, typename T, T head, T... tail>
void fill(ForwardIterator i) {
*i = head;
fill<ForwardIterator, T, tail...>(++i);
}
the following class template
template<typename T, T... args>
struct params_to_array;
template<typename T, T last>
struct params_to_array<T, last> {
static const std::size_t SIZE = 1;
typedef std::array<T, SIZE> array_type;
static const array_type params;
private:
void init_params() {
array_type result;
fill<typename array_type::iterator, T, head, tail...>(result.begin());
return result;
}
};
template<typename T, T head, T... tail>
struct params_to_array<T, head, tail...> {
static const std::size_t SIZE = params_to_array<T, tail...>::SIZE + 1;
typedef std::array<T, SIZE> array_type;
static const array_type params;
private:
void init_params() {
array_type result;
fill<typename array_type::iterator, T, last>(result.begin());
return result;
}
};
and initialized the static constants via
template<typename T, T last>
const typename param_to_array<T, last>::array_type
param_to_array<T, last>::params =
param_to_array<T, last>::init_params();
and
template<typename T, T head, T... tail>
const typename param_to_array<T, head, tail...>::array_type
param_to_array<T, head, tail...>::params =
param_to_array<T, head, tail...>::init_params();
Now the array
param_to_array<int, 1, 3, 4>::params
is a std::array<int, 3>
and contains the values 1
, 3
and 4
. I think there must be a simpler way to achieve this behavior. Any suggestions?
Edit: As Noah Roberts suggested in his answer I modified my program like the following: I wrote a new struct counting the elements in a parameter list:
template<typename T, T... args>
struct count;
template<typename T, T head, T... tail>
struct count<T, head, tail...> {
static const std::size_t value = count<T, tail...>::value + 1;
};
template<typename T, T last>
stuct count<T, last> {
static const std::size_t value = 1;
};
and wrote the following function
template<typename T, T... args>
std::array<T, count<T, args...>::value>
params_to_array() {
std::array<T, count<T, args...>::value> result;
fill<typename std::array<T, count<T, args...>::value>::iterator,
T, args...>(result.begin());
return result;
}
Now I get with
params_to_array<int, 10, 20, 30>()
a std::array<int, 3>
with the content 10
, 20
and 30
. Any further suggestions?
回答1:
There is no need to count the number of types in a parameter pack manually, thats what the sizeof...
operator is for. Additionally i'd make the iterator type for fill()
deducible, there is no need to specify it explicitly:
template<typename T, typename FwdIt>
void fill(FwdIt it) { }
template<typename T, T head, T... tail, typename FwdIt>
void fill(FwdIt it) {
*it = head;
fill<T, tail...>(++it);
}
template<class T, T... args>
std::array<T, sizeof...(args)> params_to_array() {
std::array<T, sizeof...(args)> a;
fill<T, args...>(a.begin());
return a;
};
Parameter packs however are also expandable in initializer-list contexts, which makes fill()
redundant:
template<class T, T... args>
std::array<T, sizeof...(args)> params_to_array() {
std::array<T, sizeof...(args)> a = {{args...}};
return a;
};
回答2:
The only reason I can see for a specialization for terminus in param_to_array is this line:
static const std::size_t SIZE = params_to_array<T, tail...>::SIZE + 1;
Since your params_to_array metafunction creates the array though you're going to end up instantiating arrays of size N, N-1, ...., 1. Thus I think your object could use some help from composition and the single responsibility rule. Create another metafunction that can count the elements in a parameter list and use it instead of this method. Then you can get rid of this recursion in params_to_array at the least.
来源:https://stackoverflow.com/questions/2850646/fill-container-with-template-parameters