10

I want to check if the type given to a template is inherited from a base class in my project.

It should work like one would expect it from the following example:

template< class T : public CBaseClass >
  • Is it possible to do this with templates, if not, how else can I do it?
BartoszKP
  • 33,416
  • 13
  • 100
  • 127
Oktstrom
  • 243
  • 2
  • 5

4 Answers4

14

Following an example from Stroustrup:

template<class Test, class Base>
struct AssertSameOrDerivedFrom {
  AssertSameOrDerivedFrom() { &constraints; }
public:
  static void constraints() {
    Test *pd = 0;
    Base *pb = pd;
  }
};

template<class T>
struct YourClass {
  YourClass() {
    AssertSameOrDerivedFrom<T, CBaseClass>();
  }
};

In C++0x, this becomes:

template<class T>
struct YourClass {
  static_assert(std::is_base_of<CBaseClass, T>::value);
};
Fred Nurk
  • 13,508
  • 4
  • 35
  • 61
  • @CrazyEddie: Given the code sample in the question, I believe the OP means "assert" by "check" rather than "do X if C, else Y". – Fred Nurk Feb 22 '11 at 22:49
12

You can use boost::is_base_and_derived from Boost, combined with BOOST_STATIC_ASSERT. If you are using a compiler with TR1 or C++0x support, there are equivalents of those constructs in the standard library (std::is_base_of, and the static_assert statement in C++0x).

P i
  • 26,994
  • 34
  • 144
  • 244
Jeremiah Willcock
  • 28,931
  • 7
  • 71
  • 75
6

If you want to assert, do it Nurk's way. If you want to check, use is_base_of from boost or C++0x. If you can't use either of those, use SFINAE:

template < typename Base, typename PotentialDerived >
struct is_base
{
  typedef char (&no)  [1];
  typedef char (&yes) [2];

  static yes check(Base*);
  static no  check(...);

  enum { value = sizeof(check(static_cast<PotentialDerived*>(0))) == sizeof(yes) };
};
Edward Strange
  • 39,707
  • 7
  • 69
  • 124
1

Shorter is better:

template <typename Base, typename Derived>
struct is_base {
    constexpr static bool check(Base*)   { return true; }
    constexpr static bool check(...)     { return false; }
    enum { value = check(static_cast<Derived*>(0)) };
};

Example 1:

struct A {};
struct B  : A { };

int main(void) {
    static_assert(is_base<A,B>::value, "If Error: A is not base of B");
}

Example 2:

template <bool, typename T=void>
struct Use {
    static std::string info() { return "Implementation that consider that A is not base of B"; }
};

template <typename T>
struct Use<true,T>  {
    static std::string info() { return "Implementation that consider that A is the base of B"; }
};


int main(void) {
    std::cout << Use<is_base<A,B>::value>::info(); //Implementation that consider that A is the base of B
}
user1823890
  • 664
  • 8
  • 7