14

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?

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982

1 Answers1

15

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);
}
Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
Michael Anderson
  • 70,661
  • 7
  • 134
  • 187