I'm trying to learn variadic arguments on templates. My self-imposed exercise is making a NN with static members. The idea would be to run this on a microcontroller w/o a heap. For this I want to use templates to define the cartesian product between the layers.
i.e.
weights<T,2,3,4>::type
would translate into
tuple<array<T,6>, array<T,12>>
#include<iostream>
#include <array>
template<typename T, int left, typename... U>
struct weights {
typedef std::tuple<U...> type;
};
template<typename T, int left, int right, int... other, typename... U>
struct weights {
typedef weights<T, right, other..., std::array<T, left*right>, U...>::type type;
};
int main() {
weights<int, 2, 3, 4>::type o;
return 0;
}
However the compiler seems to see the first template parameters and not the second.
This is the message I got:
weights.cpp:10:8: error: redeclared with 5 template parameters
10 | struct weights {
| ^~~~~~~
weights.cpp:5:8: note: previous declaration ‘template<class T, int left, class ... U> struct weights’ used 3 template parameters
5 | struct weights {
| ^~~~~~~
weights.cpp: In function ‘int main()’:
weights.cpp:15:25: error: type/value mismatch at argument 3 in template parameter list for ‘template<class T, int left, class ... U> struct weights’
15 | weights<int, 2, 3, 4>::type o;
| ^
weights.cpp:15:25: note: expected a type, got ‘3’
weights.cpp:15:25: error: type/value mismatch at argument 3 in template parameter list for ‘template<class T, int left, class ... U> struct weights’
weights.cpp:15:25: note: expected a type, got ‘4’
weights.cpp:15:33: error: expected initializer before ‘o’
15 | weights<int, 2, 3, 4>::type o;
| ^
How can I make the compiler see the different signatures?
CodePudding user response:
Not sure if the best waybut this is how I solved it:
#include <iostream>
#include <array>
#include <tuple>
namespace weights_ns {
template <bool last>
struct weights;
template <>
struct weights<true> {
template<typename T, typename... U>
struct supertype_0 {
template<int left> //, int right, int... other>
struct supertype_1 :
public std::tuple<U...>
{};
};
};
template <>
struct weights<false> {
template<typename T, typename... U>
struct supertype_0 {
template<int left, int right, int... other>
struct supertype_1 :
public weights_ns::weights<(sizeof...(other)==0)>::template supertype_0<T, std::array<T, left*right>, U...>::template supertype_1<right, other...>
{};
};
};
};
int main() {
std::cout << "size: " << sizeof(weights_ns::template weights<false>::template supertype_0<char>::template supertype_1<2,3,5>) << std::endl;
}
CodePudding user response:
I am not sure how to improve your answer but you could clean up the usage interface a bit
#include <iostream>
#include <array>
#include <tuple>
namespace weights_ns {
template <bool last>
struct container;
template <>
struct container<true> {
template<typename T, typename... U>
struct supertype_0 {
template<int left>
struct supertype_1 :
public std::tuple<U...>
{};
};
};
template <>
struct container<false> {
template<typename T, typename... U>
struct supertype_0 {
template<int left, int right, int... other>
struct supertype_1 :
public weights_ns::container<(sizeof...(other)==0)>::template supertype_0<T, std::array<T, left*right>, U...>::template supertype_1<right, other...>
{};
};
};
template<typename T, T... Layers>
struct weights: public weights_ns::container<(sizeof...(Layers) < 2)>::template supertype_0<T>::template supertype_1<Layers...>
{};
};
int main() {
weights_ns::weights<int, 2, 3, 5> t;
std::cout << "size: " << sizeof(t) << std::endl;
return 0;
}