In C ++ 1z with lite concepts, you can do this:
template<class T> requires std::is_base_of<Foo, T>{}() void foo(T arg) { }
at the current (experimental) implementation. This 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 did not work. You can definitely do:
template<derived_from_foo T> void foo(T arg){ }
where we have a custom concept derived_from_foo that applies if the type is derived from foo . What I do not know how to do is template concepts - concepts created from template type parameters.
In C ++ 14, two methods are presented here. First, the usual 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 infers type T from its argument. Then he tries to derive his argument like the second from the first argument.
The argument of the second type does not have a name (hence, class= ), because we use it only for the SFINAE test.
enable_if_t< condition > test. enable_if_t< condition > generates a void type if condition is true. If the condition is false, it does not work in the "immediate context", generating a replacement failure.
SFINAE - this "Replacement Error" is not an error "- if your type T generates a failure in the" direct context "of the signature of the function template, this does not create a compile-time error, and leads to results in the function template is not considered an overload in this case .
“Immediate context” is the technical term here, but basically it means that the error must be “early enough” to be caught. If this requires compiling function bodies in order to find an error, that is, not in a “direct context”.
Now this is not the only way. I personally like to hide my SFINAE code behind a splendor of respectability. Below I use tag dispatch to “hide” the crash somewhere else, instead of putting it directly 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 the send type tag , and it allows you to convert the base. tag allows us to evaluate types as values ​​and use more ordinary C ++ operations for them (instead of metaprogramming with the <> template everywhere).
Then we give foo second argument of type tag<Base> , then build it with tag<T> . This will not compile unless T is a derived type from Base .
living example .
The best part about this solution is that the code that makes it unusable seems more intuitive - tag<Unrelated> cannot convert to tag<Base> . This, however, does not prevent the function from being considered to resolve overload, which can be a problem.
Method with a smaller boiler stove:
template<class T> void foo( T t, Base*=(T*)0 ) { }
where we use the fact that pointers can be converted if there is a derivation relation 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 addition:
template<class T, class=typename std::enable_if<std::is_base_of<Foo, T>::value>::type > void foo(T arg) { }
the second C ++ 14 method above can also be translated into C ++ 11.
You can write an alias that runs 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) { }