11

Is it possible to access values of non-type template parameters in specialized template class?

If I have template class with specialization:

   template <int major, int minor> struct A {
       void f() { cout << major << endl; }
   }

   template <> struct A<4,0> {
       void f() { cout << ??? << endl; }
   }

I know it the above case it is simple to hardcode values 4 and 0 instead of using variables but what I have a larger class that I'm specializing and I would like to be able to access the values.

Is it possible in A<4,0> to access major and minor values (4 and 0)? Or do I have to assign them on template instantiation as constants:

   template <> struct A<4,0> {
       static const int major = 4;
       static const int minor = 0;
       ...
   }
stefanB
  • 77,323
  • 27
  • 116
  • 141
  • If you're specializing based on values then it implies that there is something special about those particular values. If you're using them as general values throughout the template and only treating them as special in a few places it may be that you can abstract out the special behaviour into a smaller specialized class template leaving the large template as fully generic and unspecialized. It's a bit hard to tell so can you expand your question to be more 'real'? – CB Bailey Jul 22 '09 at 06:59
  • I think the question is real enough. I have existing base class which implements specific behavior based on the protocol version. Previously it had a member that return the protocol version - as that member was no longer available there was a logging method that was including protocol version in output. I could just hardcode the values but I wanted to know if there's better way. The accepted answer provides good way of doing it - I'm actually using traits in similar way in other places - for getting the parameter types but the intent is the same. – stefanB Jul 22 '09 at 07:37

4 Answers4

18

This kind of problem can be solved by having a separate set of "Traits" structs.

// A default Traits class has no information
template<class T> struct Traits
{
};

// A convenient way to get the Traits of the type of a given value without
// having to explicitly write out the type
template<typename T> Traits<T> GetTraits(const T&)
{
    return Traits<T>();
}

template <int major, int minor> struct A 
{ 
    void f() 
    { 
        cout << major << endl; 
    }   
};

// Specialisation of the traits for any A<int, int>
template<int N1, int N2> struct Traits<A<N1, N2> >
{
    enum { major = N1, minor = N2 };
};

template <> struct A<4,0> 
{       
    void f() 
    { 
        cout << GetTraits(*this).major << endl; 
    }   
};
stefanB
  • 77,323
  • 27
  • 116
  • 141
Andrew Shepherd
  • 44,254
  • 30
  • 139
  • 205
1

Not really an answer to your question, but you could enumerate them, viz:

enum{
 specialisationMajor=4,
 specialisationMinor=0
};

template <> struct A<specialisationMajor,specialisationMinor> {
    static const int major = specialisationMajor;
    static const int minor = specialisationMinor;
    ...
}
Dave Gamble
  • 4,146
  • 23
  • 28
  • I'm trying to avoid defining another set of variables ... that was the beauty of having those template parameters, I dont' usually want to access the values ... but nevermind, but thanks – stefanB Jul 22 '09 at 00:23
0

Not really an answer to your question, but the idea below helped me once:

#include <iostream>

template <int major, int minor, int= major, int= minor> struct A {
    void f() { std::cout << major << '\n'; }
};

template <int major, int minor> struct A<major, minor, 4, 0> {
    void f() { std::cout << major << ':' << minor << '\n'; }
};

int main()
{
    A<3, 3>().f();
    A<4, 0>().f();
}
0

No, you don't have access to the specialized non-type template parameters. But here is a way to not repeat yourself in the implementation of f:

   template <int major, int minor>
   struct f_impl
   {
       void f() { cout << major << endl; }
   };

   template <int major, int minor>
   struct A : public f_impl<major, minor>
   {};

   template <> struct A<4,0> : public f_impl<4,0>
   {};

For this example, one doesn't gain all too much, as one needs to write the 4,0 twice (--so you could write it as well a second time in the cout in your OP). But it starts to pay out if you have more functions using the template parameters.

davidhigh
  • 14,652
  • 2
  • 44
  • 75