Search code examples
c++templatesparameterstemplate-templates

How to use a template class as a template parameter?


I have a class which stores a scalar along with associated physical dimension exponents:

template <int L, int M, int T, int C, int K, int S, int I>
class Dimension<L, M, T, C, K, S, I>
{
    ...
}

I'd like to build a vector like class (Vec), with static storage, which stores an array of these objects. I would presume the Vec class template would look something like:

template <Dimension<L, M, T, C, K, S, I> D, size_t N>
class Vec
{
    ...
}

But this causes an error as the template parameter D depends on template parameters (L, M, T, C, K, S, I). I have tried a couple of things by brute force but I'm just guessing and would prefer to be shown the correct method by someone with expertise in the matter.

I have seen examples where template<class> is inserted into the template arguments, but I don't quite understand what it achieves or even if it's actually applicable. Thanks very much for your help.

Note that I am aware that these class examples have been implemented before, probably in better ways.

Edit: Fixed a typo and changed name of Vec class.


Solution

  • If I understand correctly, you need template template arguments.

    Anyway, first of all remember to use the word struct (or class) for Dimension

    template <int L, int M, int T, int C, int K, int S, int I>
    struct Dimension
     { };
    

    Second, you can declare a type vect (please, not vector, that can clash with the standard std::vector) as follows

    template <typename, std::size_t>
    struct vect;
    

    as receiving a type and an unsigned integer.

    Then you can implement a partial specialization (with std::cout exaple for the template integer values) as follows

    template <template <int, int, int, int, int, int, int> class Dim,
             int L, int M, int T, int C, int K, int S, int I, std::size_t N>
    struct vect<Dim<L, M, T, C, K, S, I>, N>
     {
       vect ()
        { std::cout << " - L: " << L << " - M: " << M << " - T: " << T
                    << " - C: " << C << " - K: " << K << " - S: " << S
                    << " - I: " << I << " - N: " << N << std::endl; }
     };
    

    You can use this vect as follows

    vect<Dimension<2, 3, 5, 7, 11, 13, 17>, 42> v;
    

    This works with C++98 also.

    If you can use C++11 or newer, you can use variadic arguments so the vect specialization can be simplified (a little) as follows

    template <template <int...> class Dim,
             int L, int M, int T, int C, int K, int S, int I, std::size_t N>
    struct vect<Dim<L, M, T, C, K, S, I>, N>
     { /* ... */ };
    

    or, using variadic arguments, a little more

    template <template <int...> class Dim, int ... Is, std::size_t N>
    struct vect<Dim<Is...>, N>
     { /* ... */ };
    

    but, in this case, it's a little more complicated to use the single Is... values.

    But, if you can use at least C++11, I strongly suggest (following the example of Miles Budnek) the use of std::array.