9

I want to specialize a class template with the following function:

template <typename T>
class Foo
{
public:
    static int bar();
};

The function has no arguments and shall return a result based on the type of Foo. (In this toy example, we return the number of bytes of the type, but in the actual application we want to return some meta-data object.) The specialization works for fully specified types:

// specialization 1: works
template <>
int Foo<int>::bar() { return 4; }

// specialization 2: works
template <>
int Foo<double>::bar() { return 8; }

// specialization 3: works
typedef pair<int, int> IntPair;
template <>
int Foo<IntPair>::bar() { return 2 * Foo<int>::bar(); }

However, I would like to generalize this to types that depend on (other) template parameters themselves. Adding the following specialization gives a compile-time error (VS2005):

// specialization 4: ERROR!
template <>
template <typename U, typename V>
int Foo<std::pair<U, V> >::bar() { return Foo<U>::bar() + Foo<V>::bar(); }

I am assuming this is not legal C++, but why? And is there a way to implement this type of pattern elegantly?

kmhofmann
  • 514
  • 6
  • 13
  • 1
    Note, however, that you don't need any specializations for returning the size of T: `static int Foo() { return sizeof(T); }`. I wonder if that kind of pattern might not help with your real problem. – UncleBens Nov 25 '09 at 15:28

2 Answers2

7

Partitial specialization is valid only for classes, not functions.

Workaround:

template <typename U, typename V>
class Foo<std::pair<U, V> > { 
public:
 static int bar() { return Foo<U>::bar() + Foo<V>::bar(); }
};

If you does not want to specialize class fully, use auxiliary struct

template<class T>
struct aux {
  static int bar();
};

template <>int aux <int>::bar() { return 4; }
template <>int aux <double>::bar() { return 8; }

template <typename U, typename V>
struct aux <std::pair<U, V> > { 
  static int bar() { return Foo<U>::bar() + Foo<V>::bar(); }
};

template<class T>
class Foo : aux<T> {
  // ... 
};
Alexey Malistov
  • 26,407
  • 13
  • 68
  • 88
  • 1
    In the example all the specializations are class specializations – TimW Nov 25 '09 at 15:10
  • 1
    Yes. right. Function partitial specialize is prohibitted. It is possible to create Base class for function bar only. – Alexey Malistov Nov 25 '09 at 15:14
  • @TimW, in the question, the trick is that the class is not specialized. This is out of the Standard: "A member function, a member class or a static data member of a class template may be explicitly specialized for a class specialization that is implicitly instantiated; If such an explicit specialization for the member of a class template names an implicitly-declared special member function (clause 12), the program is ill-formed.". It's a specialization for one given implicit instantiation (thus, no template parameter-dependency) of that template (not for any partial specialization). – Johannes Schaub - litb Nov 25 '09 at 15:16
  • @litb So if he did not write the specialized class definitions, his program is ill-formed. I just the assumption that he just left them out of the example – TimW Nov 25 '09 at 15:25
  • Nice explanation and workaround. However the workaround is limited, because sometimes one has to specialize an existing class. For example I had to specialize a single `static` function of `boost::numeric::interval_lib::checking_base` and for that I had to copy the whole class just to change a bit of `boost::numeric::interval_lib::checking_base::empty_lower()`. (By the way I needed to specially when `T` matches `quantity`.) – alfC Sep 02 '14 at 22:18
5

It is perfectly legal in C++, it's Partial Template Specialization.
Remove the template <> and if it doesn't already exists add the explicit class template specialization and it should compile on VS2005 (but not in VC6)

// explicit class template specialization
template <typename U, typename V>
class Foo<std::pair<U, V> >
{
public:
    static int bar();
};

template <typename U, typename V>
int Foo<std::pair<U, V> >::bar() { return Foo<U>::bar() + Foo<V>::bar(); }
TimW
  • 8,351
  • 1
  • 29
  • 33
  • 1
    @litb As far a I can see all his functions are class specializations. I don't see any function template, do you? – TimW Nov 25 '09 at 15:14
  • @TimW: When you declare a class template, each member function is an independent function template. The OP is trying to specialize a member function template without specializing the entire class template. That's the point. However, partial specialization is not supported for function templates. That's the problem. – AnT stands with Russia Nov 25 '09 at 15:23
  • @TimW, there is no function template. But there is also no explicit class template specialization. See above for the Standard quotation: This is a special case in the Standard, and allows explicitly specializing separate non-template members of class templates, without explicitly specializing their whole class template. It works by naming a given implicit instantiation (in his example, for instance `Foo` or `Foo`) which in absence of any partial specializations of `Foo` will select the primary template and specialize the `bar` member thereof. – Johannes Schaub - litb Nov 25 '09 at 15:24
  • I just made the assumption that he was to lazy and left the definition s of the class specializations out of the example – TimW Nov 25 '09 at 15:35