问题
I had nested partially specialized template code working with VS 2015 until I discovered that it was not standards-compliant. I want it to be so I twisted my code to overcome the former issue and also that one and have now hit a hard wall.
Using variadic templates and partial specialization I would like to fill an array at compile-time given a fixed set of parameters.
What I want to achieve also seems similar to this answer but I did not manage to make it work.
Consider the following program:
#include <cstdlib>
template <typename T, std::size_t Size>
struct Array;
template <typename T, std::size_t Size, std::size_t Iteration, typename ...Args>
struct ArrayFiller {
inline
static void fill(Array<T, Size>& a, const Args&... args) {
ArrayFiller<T, Size, Iteration, Args...>::fill_recursive(a, args...);
}
inline
static void fill_recursive(Array<T, Size>& a, const T& i, const Args&... args) {
a.data[Size - Iteration - 1] = i;
ArrayFiller<T, Size, Iteration - 1>::fill_recursive(a, args...);
}
};
template <typename T, std::size_t Size>
struct ArrayFiller<T, Size, 0> {
inline
static void fill_recursive(Array<T, Size>& a, const T& i) {
a.data[Size - 1] = i;
}
};
template <typename T, std::size_t Size>
struct Array {
T data[Size];
template <typename ...Args>
Array(const Args&... args) {
ArrayFiller<T, Size, Size - 1, Args...>::fill(*this, args...);
}
};
int main() {
Array<int, 2> c(42, -18);
return 0;
}
...and the beginning of its g++ -std=c++14 -pedantic -Wall -Wextra
output (as of version 5.3.0):
main.cpp: In instantiation of ‘static void ArrayFiller<T, Size, Iteration, Args>::fill(Array<T, Size>&, const Args& ...) [with T = int; long unsigned int Size = 2ul; long unsigned int Iteration = 1ul; Args = {int, int}]’:
main.cpp:34:54: required from ‘Array<T, Size>::Array(const Args& ...) [with Args = {int, int}; T = int; long unsigned int Size = 2ul]’
main.cpp:39:28: required from here
main.cpp:10:65: error: no matching function for call to ‘ArrayFiller<int, 2ul, 1ul, int, int>::fill_recursive(Array<int, 2ul>&, const int&, const int&)’
ArrayFiller<T, Size, Iteration, Args...>::fill_recursive(a, args...);
^
main.cpp:14:17: note: candidate: static void ArrayFiller<T, Size, Iteration, Args>::fill_recursive(Array<T, Size>&, const T&, const Args& ...) [with T = int; long unsigned int Size = 2ul; long unsigned int Iteration = 1ul; Args = {int, int}]
static void fill_recursive(Array<T, Size>& a, const T& i, const Args&... args) {
^
main.cpp:14:17: note: candidate expects 4 arguments, 3 provided
Basically the compiler complains that there is no matching function because from what I understand the parameter pack is expanded either too "soon" or too "late" in my logic: the const T& i
argument in the recursive call messes up the expansion.
How would you fix it?
I am also interested in alternate / better / cleaner solutions.
回答1:
Is a solution not based on template recursion acceptable in your use case? wandbox link
template <typename T, std::size_t Size>
struct Array {
T data[Size];
template <typename ...Args>
constexpr Array(const Args&... args) : data{args...} {
}
};
int main() {
Array<int, 2> c(42, -18);
assert(c.data[0] == 42);
assert(c.data[1] == -18);
constexpr Array<int, 2> cc(42, -18);
static_assert(cc.data[0] == 42);
static_assert(cc.data[1] == -18);
}
回答2:
I might be off target here but based on this requirement "... I would like to fill an array at compile-time given a fixed set of parameters." and this code:
int main() {
Array<int, 2> c(42, -18);
return 0;
}
I have been left wondering is this not solvable with a normal array declaration and initialization?
int main() {
constexpr int c []{42, -18};
static_assert( c[0] == 42 ) ;
// and so on
return 0;
}
In a comment to the previous answer, you are mentioning some setter? There must be something missing in here... In case you need to have this class Array
as above, perhaps the simplest way to do so is this:
template<typename T, T ... V >
struct Array
{
constexpr static T data_[]{ V... };
// not strictly necessary
constexpr static size_t size{ sizeof(data_) / sizeof(T) };
};
Usage is this:
// length is not required for declaration
using int_array_of_4 = Array<int,1,2,3,4> ;
static_assert( int_array_of_4::data_[0] == 1) ;
// and so on
But I might be barking on the wrong tree here?
来源:https://stackoverflow.com/questions/39169965/how-to-fill-array-with-contents-of-a-template-parameter-pack