3

I have a (free) function template that looks like this

template <typename T>
T get();

I now want to specialize this function for a class, which itself is a template. But my compiler doesn't want to compile it, and I'm asking now if that is even possible and how I could achieve it. Just for the idea, the code could look as follows: (Doesn't compile)

template <>
template <typename T>
foo_type<T> get<foo_type<T>>()
cooky451
  • 3,460
  • 1
  • 21
  • 39

2 Answers2

4

What you're doing is called partial specialization of function template. But partial specialization of function template is not allowed. Overloading of function template is allowed, but in this case, it is not possible either, as the function has only return type, and overloading on return type is not allowed.

So the solution is this:

namespace details
{
     template <typename T>
     struct worker
     {
         static T get();
     };

     template <typename T> //partial specialization of class is allowed
     struct worker<foo<T>>
     {
         static foo<T> get();
     };

}

template <typename T>
T get()
{
  return details::worker<T>::get();
}

You could also use overloads if you define them to take one argument so as to make overload valid:

namespace details
{
     template <typename T>
     static T get(T*); 

     template <typename T> 
     static foo<T> get(foo<T>*); //now the overload is valid

}

template <typename T>
T get()
{
  return details::get<T>(static_cast<T*>(0));
}

Note that the argument static_cast<T*>(0) is used to help the compiler to select the correct overload. If T is other than foo<U>, then the first overload will be selected as the type of the argument passed to it will be T* as opposed to foo<U>*. If T is foo<U>, then the second overload will be selected by the compiler because it is more specialized, and can accept the argument passed to it which is foo<U>* in this case.

Nawaz
  • 353,942
  • 115
  • 666
  • 851
  • Now, seeing the solution, it's painfully obvious. Thank you! But now I get a linker error.. any idea? – cooky451 Mar 03 '12 at 01:45
  • @Xeo: Oops. Yes. You're right. When I posted it, I felt that I'm doing something wrong, but couldn't figure out that. – Nawaz Mar 03 '12 at 01:46
  • 1
    @cooky: Did you put your template function body in a .cpp? :) – Xeo Mar 03 '12 at 01:54
  • 1
    No, the linking error came up when just overloading the function. Kind of funny, don't ask me what the compiler did there. (Not very much obviously, he just entrusted the linker with his tasks ;)) -- However, this works now, thanks are going to both of you, now I have to decide what to accept as answer. Maybe I roll a dice. ;) – cooky451 Mar 03 '12 at 02:01
  • static_cast(nullptr) – Janek Olszak Aug 19 '14 at 08:10
2

As Nawaz said, the standard just doesn't allow you to do that. You could however extract the implementation into the static method of a class and partially specialize that class.

template<class T>
struct get_impl{
  static T get(){ ... }
};

template<class T>
struct get_impl<foo_type<T> >{
  static foo_type<T> get(){ ... }
};

template<class T>
T get(){ return get_impl<T>::get(); }
Xeo
  • 129,499
  • 52
  • 291
  • 397