views:

220

answers:

2

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?

+1  A: 

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
@litb As far a I can see all his functions are class specializations. I don't see any function template, do you?
TimW
@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.
AndreyT
@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<int>` or `Foo<double>`) which in absence of any partial specializations of `Foo` will select the primary template and specialize the `bar` member thereof.
Johannes Schaub - litb
I just made the assumption that he was to lazy and left the definition s of the class specializations out of the example
TimW
Why the 2 down votes, please explain.
TimW
+3  A: 

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
In the example all the specializations are class specializations
TimW
Yes. right. Function partitial specialize is prohibitted. It is possible to create Base class for function bar only.
Alexey Malistov
@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
@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