c++ template specialization for all subclasses
I know this question has been answered but nobody mentioned that std::enable_if can be used as a second template parameter like this:
#include <type_traits>
class A {};
class B: public A {};
template<class T, typename std::enable_if<std::is_base_of<A, T>::value, int>::type = 0>
int foo(T t)
{
return 1;
}
You can do what you want but not how you are trying to do it! You can use std::enable_if
together with std::is_base_of
:
#include <iostream>
#include <utility>
#include <type_traits>
struct Bar { virtual ~Bar() {} };
struct Foo: Bar {};
struct Faz {};
template <typename T>
typename std::enable_if<std::is_base_of<Bar, T>::value>::type
foo(char const* type, T) {
std::cout << type << " is derived from Bar\n";
}
template <typename T>
typename std::enable_if<!std::is_base_of<Bar, T>::value>::type
foo(char const* type, T) {
std::cout << type << " is NOT derived from Bar\n";
}
int main()
{
foo("Foo", Foo());
foo("Faz", Faz());
}
Since this stuff gets more wide-spread, people have discussed having some sort of static if
but so far it hasn't come into existance.
Both std::enable_if
and std::is_base_of
(declared in <type_traits>
) are new in C++2011. If you need to compile with a C++2003 compiler you can either use their implementation from Boost (you need to change the namespace to boost
and include "boost/utility.hpp"
and "boost/enable_if.hpp"
instead of the respective standard headers). Alternatively, if you can't use Boost, both of these class template can be implemented quite easily.
I would use std::is_base_of
along with local class as :
#include <type_traits> //you must include this: C++11 solution!
template<typename T>
void foo(T a)
{
struct local
{
static void do_work(T & a, std::true_type const &)
{
//T is derived from Bar
}
static void do_work(T & a, std::false_type const &)
{
//T is not derived from Bar
}
};
local::do_work(a, std::is_base_of<Bar,T>());
}
Please note that std::is_base_of
derives from std::integral_constant
, so an object of former type can implicitly be converted into an object of latter type, which means std::is_base_of<Bar,T>()
will convert into std::true_type
or std::false_type
depending upon the value of T
. Also note that std::true_type
and std::false_type
are nothing but just typedefs, defined as:
typedef integral_constant<bool, true> true_type;
typedef integral_constant<bool, false> false_type;
I like this clear style:
void foo_detail(T a, const std::true_type&)
{
//do sub-class thing
}
void foo_detail(T a, const std::false_type&)
{
//do else
}
void foo(T a)
{
foo_detail(a, std::is_base_of<Bar, T>::value);
}