2

I'd like my template function to accept as an argument only a class that inherits from a base class. I think a code snippet explains it better.

class Base
{
    // Some magic
}

class Derived : public Base
{
    // Even more magic
}

class Foo
{}

// Is it possible to tell template to accept only classes derived from Base?
template<class T>
do_something(T obj)
{
    // Perform some dark magic incantations on obj
}

int main()
{
    Foo foo;
    Derived derived;
    do_something<Derived>(derived); // Normal
    do_something<Foo>(foo); // Compilation error if I understand templates correctly
}
Sherlock Holmes
  • 191
  • 1
  • 8

1 Answers1

2

Pre-C++20 you can use enable_if coupled with checking is_base_of:

template<class T, std::enable_if_t<std::is_base_of_v<Base, T> && !std::is_same_v<Base, T>, int> = 0>
void do_something(T obj)
{
    // Perform some dark magic incantations on obj
}

Note that I've explicitly disallowed the type to be an instance of Base (because is_base_of considers a type to be a base of itself). If you want to allow instances of Base, then remove && !std::is_same_v<Base, T>

Live Demo


In C++20 we can almost directly translate our enable_if into a requires expression:

template<class T>
requires (std::is_base_of_v<Base, T> && !std::is_same_v<Base, T>)
void do_something(T obj)
{
   // ...
}

Concepts Demo

Or, if you want to allow instances of Base, you can use the built-in derived_from Concept:

template<class T>
requires std::derived_from<T, Base>
void do_something(T obj)
{
   // ...
}

Concepts Demo 2

AndyG
  • 39,700
  • 8
  • 109
  • 143