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.
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);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With