Partial specialization of templates with integer parameters

Nicol Bolas picture Nicol Bolas · Oct 2, 2012 · Viewed 7.7k times · Source

I'm trying to do some partial specialization stuff. I have a tuple, and I want to iterate from a certain element index to the first tuple index, accumulating a value from each type in the tuple. This would seem to be a simple matter of using a recursive template instantiation.

The problem is, I can't seem to get the recursion to work. In order to stop the recursion, I need to partially specialize the template function at tuple index 0. That seemed simple enough, but it's not working.

Note: I've removed the actual tuple stuff from the example, as it's irrelevant; it's the template specialization that's not working.

template<int Index, typename Tpl>
size_t CalcInterleaveByteOffset(const Tpl &t)
{
    size_t prevOffset = CalcInterleaveByteOffset<Index - 1>(t);
    return prevOffset + sizeof(Tpl);
}

template<typename Tpl>
size_t CalcInterleaveByteOffset<0, Tpl>(const Tpl &t)
{
    return 0;
}

GCC simply says that this kind of specialization is not allowed. Is that true? Is there some other way to handle this sort of thing?

Answer

Michael Anderson picture Michael Anderson · Oct 2, 2012

As a rule any form of partial template specialisation is not allowed for functions. However it is allowed for classes. So the solution is simply to move your function to a static member of a templated holder class.

If you need to deduce the template arguments, you can then just create a wrapper function that calls the templated class.

The result is something like this:

template<int Index, typename Tpl>
class CalcInterleaveByteOffsetImpl
{
  static size_t CalcInterleaveByteOffset(const Tpl &t)
  {
    // This is OK it calls the wrapper function
    // You could also do 
    // size_t prevOffset = CalcInterleaveByteOffsetImpl<Index - 1, Tpl>::CalcInterleaveByteOffset(t);
    size_t prevOffset = ::CalcInterleaveByteOffset<Index - 1>(t);
    return prevOffset + sizeof(Tpl);
  }
};

template<typename Tpl>
class CalcInterleaveByteOffsetImpl<0, Tpl>
{
  static size_t CalcInterleaveByteOffset(const Tpl &t)
  {
    return 0;
  }
};

template<int Index, typename Tpl>
size_t  CalcInterleaveByteOffset(const Tpl &t)
{
   return CalcInterlaveByteOffsetImpl<Index,Tpl>::CalcInterleaveByteOffset(t);
}