6

Considering class templates, it is possible to provide template specializations for certain types of groups using type traits and dummy enabler template parameters. I've already asked that earlier.

Now, I need the same thing for function templates: I.e., I have a template function and want a specialization for a group of types, for example, all types that are a subtype of a class X. I can express this with type traits like this:

std::enable_if<std::is_base_of<X, T>::value>::type

I thought about doing it this way:

template <typename T, typename ENABLE = void>
void foo(){
    //Do something
}

template <typename T>
void foo<T,std::enable_if<std::is_base_of<A, T>::value>::type>(){
    //Do something different
}

However, this does not work since partial specialization is not allowed for function templates. So how to do it then? Maybe a default parameter with the type trait as type? But how does the code look like then?

Community
  • 1
  • 1
gexicide
  • 38,535
  • 21
  • 92
  • 152
  • What are you actually using this for? Prefer to overload functions rather than specialise their templates. Hopefully your intended usage allows that. – Seth Carnegie Sep 03 '12 at 14:50

4 Answers4

9

Overloads:

void foo_impl(T, std::false_type);

void foo_impl(T, std::true_type);

foo(T t) { foo_impl(t, std::is_base_of<A, T>()); }
Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
4

The closest to what you're asking is enable_if on the return type:

template<typename T> typename std::enable_if<std::is_same<T, int>::value>::type foo();
template<typename T> typename std::enable_if<std::is_same<T, char>::value>::type foo();

However, dispatching to a helper function or class is likely to be more readable and efficient.

Helper function:

template<typename T> void foo_helper(std::true_type);
template<typename T> void foo_helper(std::false_type);
template<typename T> void foo() { foo_helper(std::is_same<T, int>()); }

Helper class:

template<typename T, bool = std::is_same<T, int>::value> struct foo_helper {};
template<typename T> struct foo_helper<T, true> { static void foo(); };
template<typename T> struct foo_helper<T, false> { static void foo(); };
template<typename T> void foo() { foo_helper<T>::foo(); }
ecatmur
  • 152,476
  • 27
  • 293
  • 366
  • okay, by using the return type, I can even omit the default parameter – gexicide Sep 03 '12 at 14:57
  • 1
    @gexicide however, you have to do a specialisation for every function definition, so you lose the ability to have a "catch-all" definition like you can have for class templates. – Seth Carnegie Sep 03 '12 at 15:01
0

Do the actual implementation (partial specializations etc..) in class templates and write a small wrapper template function that does nothing but call a static function in your class templates.

ltjax
  • 15,837
  • 3
  • 39
  • 62
0

Tried a few things and finally came up with the correct syntax myself - sorry for asking. I didn't know that enable_if has a second parameter. By using this parameter and a default value, it is possible.

Here is the answer

template<typename T>
void foo(typename std::enable_if<std::is_base_of<A, T>::value,int>::type ENABLER = 0){
    std::cout << "T is a subclass of A!";
}

template<typename T>
void foo(typename std::enable_if<!std::is_base_of<A, T>::value,int>::type ENABLER = 0){
    std::cout << "T is NOT a subclass of A";
}
gexicide
  • 38,535
  • 21
  • 92
  • 152