In C++1z with concepts lite, you can do this:
template<class T>
requires std::is_base_of<Foo, T>{}()
void foo(T arg) {
}
under the current (experimental) implementation. Which is pretty clean and clear. There may be a way to do something like:
template<derived_from<Foo> T>
void foo(T arg) {
}
but I haven't worked it out. You can definitely do:
template<derived_from_foo T>
void foo(T arg){
}
where we have a custom concept called derived_from_foo
that applies iff the type is derived from foo
. What I don't know how to do is template concepts -- concepts generated from template type parameters.
In C++14, here are two methods. First, normal SFINAE:
template<class T,
class=std::enable_if_t<std::is_base_of<Foo, T>{}>
>
void foo(T arg) {
}
here we create a template that deduces the type T
from its argument. It then tries to deduce its second type argument from the first argument.
The second type argument has no name (hence class=
), because we are only using it for a SFINAE test.
The test is enable_if_t< condition >
. enable_if_t< condition >
generates the type void
if condition
is true. If condition
is false, it fails in "the immediate context", generating a substitution failure.
SFINAE is "Substitution failure is not an error" -- if your type T
generates a failure in the "immediate context" of the function template signature, this doesn't generate a compile-time error, but instead results in the function template not being considered a valid overload in this case.
"Immediate context" is a technical term here, but basically it means the error has to be "early enough" to be caught. If it requires compiling bodies of functions to find the error, that is not in "the immediate context".
Now, this isn't the only way. I personally like hiding my SFINAE code behind a gloss of respectability. Below, I use tag dispatching to "hide" the failure somewhere else, instead of putting it right up front in the function signature:
template<class T>
struct tag {
using type=T;
constexpr tag(tag const&) = default;
constexpr tag() = default;
template<class U,
class=std::enable_if_t<std::is_base_of<T,U>{}>
>
constexpr tag(tag<U>) {}
};
struct Base{};
struct Derived:Base{};
template<class T>
void foo( T t, tag<Base> = tag<T>{} ) {
}
here we create a tag
dispatch type, and it allows conversion to base. tag
lets us worth with types as values, and use more normal C++ operations on them (instead of template-like metaprogramming <>
s all over the place).
We then give foo
a second argument of type tag<Base>
, then construct it with a tag<T>
. This fails to compile if T
is not a derived type from Base
.
live example.
The nice thing about this solution is that the code that makes it not work seems more intuitive -- tag<Unrelated>
cannot convert to tag<Base>
. This does not, however, prevent the function from being considered for overload resolution, which can be a problem.
A way with less boiler plate is:
template<class T>
void foo( T t, Base*=(T*)0 ) {
}
where we use the fact that pointers can be converted iff there is a derivation relationship between them.
In C++11 (and without constexpr
support), we first write a helper:
namespace notstd {
template<bool b, class T=void>
using enable_if_t=typename std::enable_if<b,T>::type;
}
then:
template<class T,
class=notstd::enable_if_t<std::is_base_of<Foo, T>::value>
>
void foo(T arg) {
}
if you don't like the helper, we get this ugly extra:
template<class T,
class=typename std::enable_if<std::is_base_of<Foo, T>::value>::type
>
void foo(T arg) {
}
the second C++14 technique above can also be translated to C++11.
You can write an alias that does the test if you want:
template<class U>
using base_test=notstd::enable_if_t<std::is_base_of<Base, U>::value>;
template<class T,
class=base_test<T>
>
void foo(T arg) {
}