3

I have been checking on the intrnet for a while and haven found any answer for my question. I would like to know if C++ supports bounded polymorphism, and/or F-bounded polymorphism.

For instance, in Java programmers can do this (boundedn polymorphism):

<T extends Car> void startEngine(T c) {/*body method*/}

and this (F-Bounded polymorphism):

<T extends Comparable<T>> void compareWith(T c) {/*body method*/}

Is anything equivalent in C++?

Thanks!

excalibur1491
  • 1,201
  • 2
  • 14
  • 29

2 Answers2

8
<T extends Car> void startEngine(T c) {}

In C++, equivalent of the above would be this:

template<typename T, typename Unused= typename std::enable_if<std::is_base_of<Car,T>::value>::type>
void startEngine(T c) {}

Alright the syntax is ugly, but you can make it a bit nicer with alias as:

//first define a (reusuable) alias
template<typename D, typename B>
using extends = typename std::enable_if<std::is_base_of<B,D>::value>::type;

//then your code would look like this
template<typename T, typename Unused=extends<T,Car> >
void startEngine(T c) 
{
}

Or you can use static_assert, as the other answer explains. But std::enable_if and static_assert are not equivalent. While static_assert gives you an opportunity to produce good error messages, std::enable_if helps you to resolve overloads, which means the above function will be invoked only if Car is a base of T, else other overload, if any, will be selected/considered. With static_assert, that is not possible: it simply fails and stop — it doesn't look further for overloads.

Likewise,

//then your code would look like this
template<typename T, typename Unused=extends<T,Comparable<T>> >
void compareWith(T c) 
{
}

This technique is known as:

Hope that helps.

Nawaz
  • 353,942
  • 115
  • 666
  • 851
  • Woow, thanks. Just one question: what is going to be the value of Unused if T is not a sublcass of Car? I'm not sure I understand what if_derived_from returns. – excalibur1491 Oct 30 '13 at 17:15
  • Alright, now the examples are equivalent :) However, I would have fixed that by declaring `template using if_derived_from = typename enable_if{}>::type;` (reversing the arguments) and using `Unused=if_derived_from` (checking if `T` is derived from `Car`, equivalent to `is_base_of` checks if `Car` is a base of `T`). – dyp Oct 30 '13 at 17:16
  • @DyP: Ah. Thats better. But `extends` looks even better: it makes the C++ code very much closer to Java code. – Nawaz Oct 30 '13 at 17:24
  • 2
    @excalibur1491 If the type is not a subclass of Car then instantiating the template fails; There's no 'Unused' to have a type in that case. If the type is derived from Car then Unused does have a type, but it doesn't matter what it is because it's not used. Unused is just a dummy parameter to let you put the 'if_derived_from' expression in there. What 'if_derived_from' does is say "if the type is derived from Car then go ahead and instantiate this template so it can be used. Otherwise pretend like this template doesn't exist." This is based on a C++ trick known as SFINAE. – bames53 Oct 30 '13 at 17:26
  • @excalibur1491: If `T` doesn't derive from `Car`, then `Unused` wouldn't be deduced, and that is the whole point, the substitution fails, so the compiler would reject this function, and try some other overload if available. – Nawaz Oct 30 '13 at 17:29
  • @bames53 Thanks! Now I get it (the "Otherwise pretend like this template doesn't exist." was really helpful!). Also thanks Nawaz ;) – excalibur1491 Oct 30 '13 at 17:30
  • @bames53: It is not `if_derived_from` anymore. It is `extends`. Sorry for the confusion. – Nawaz Oct 30 '13 at 17:30
  • I prefer to define the last argument as value rather than type, this looks cleaner and works the same way `template = 0>` – PierreBdR Nov 21 '14 at 15:16
4

In C++11 you can use static_assert and type traits to check if template parameter is a class derived from a specific class. For example:

#include <type_traits>

class Base {};
class Derived : Base {};
class Other {};

template<class T>
void foo(T t)
{
    static_assert(std::is_base_of<Base, T>::value, "T must be a class derived from Base");
}

int main()
{
    foo(Derived()); // ok
    foo(Base()); // ok
    foo(Other()); // error: static assertion failed: T must be a class derived from Base
}
Sergey Ch.
  • 628
  • 1
  • 7
  • 17
  • This solution produces a nicer/cleaner diagnostic message, but doesn't allow overloading of `foo` for different `Base` types. (Use where appropriate.) – dyp Oct 30 '13 at 17:05