Home > Software design >  Different template signatures
Different template signatures

Time:12-17

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;
}
  • Related