c++ template specialization for all subclasses

2019-03-19 08:09发布

I need to create a template function like this:

template<typename T>
void foo(T a)
{
   if (T is a subclass of class Bar)
      do this
   else
      do something else
}

I can also imagine doing it using template specialization ... but I have never seen a template specialization for all subclasses of a superclass. I don't want to repeat specialization code for each subclass

4条回答
ゆ 、 Hurt°
2楼-- · 2019-03-19 08:26

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);
}
查看更多
走好不送
3楼-- · 2019-03-19 08:29

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.

查看更多
我欲成王,谁敢阻挡
4楼-- · 2019-03-19 08:36

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;
}
查看更多
何必那么认真
5楼-- · 2019-03-19 08:39

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;
查看更多
登录 后发表回答