7

More specifically, let's say I have a class template with parameters A and B, and I would like to have a compiler error (when the template is being instantiated) if B is not derived from A.

template<class A, class B>
class Foo
{
    // static_assert(B is derived from A)
};
Timo
  • 5,125
  • 3
  • 23
  • 29

3 Answers3

10

This has been asked so very many times before, but it's so simple I'll post the solution again:

~Foo()
{
    A* p = (B*)0; // B is required to be a subtype of A
}
Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
  • I like this one for its simplicity. I was thinking way too complicated. :) – Timo Dec 26 '10 at 00:40
  • This doesn't work as a good test if `B` has a conversion operator to `A`. – rubenvb Apr 20 '13 at 15:25
  • See [here](http://coliru.stacked-crooked.com/view?id=f4599b11c9f593a9790951a4b0fb36d4-50d9cfc8a1d350e7409e81e87c2653ba) for why this is not the right way. – rubenvb Apr 20 '13 at 15:31
  • @rubenvb: My answer is perfectly fine. A user-defined conversion from `B` to `A` does not create a conversion from `B*` to `A*`. And your code snippet is completely unrelated. – Ben Voigt Apr 20 '13 at 19:52
9

Check boost::is_base_of. And if you want to make it yourself try Alexyey's code from this question:

typedef char (&yes)[1];
typedef char (&no)[2];

template <typename B, typename D>
struct Host
{
  operator B*() const;
  operator D*();
};

template <typename B, typename D>
struct is_base_of
{
  template <typename T> 
  static yes check(D*, T);
  static no check(B*, int);

  static const bool value = sizeof(check(Host<B,D>(), int())) == sizeof(yes);
};

Edit. Writing static assert is not a big deal, but here it is:

#define STATIC_ASSERT(expr, msg) \
  { stat_assert<((expr) != 0)> ERROR_##msg; (void)ERROR_##msg; } 

template<int>
struct stat_assert;

template<>
struct stat_assert<true>{};

Edit2. And the whole working thing if you don't know how to merge these things: Code on ideone

Community
  • 1
  • 1
Pawel Zubrycki
  • 2,703
  • 17
  • 26
  • This is elegant (I never saw this non-ellipsis way of doing SFINAE), but I'm tempted to down vote since it is not what OP wants: this does not trigger a compiler error when instantiating something with B and D such that B is not an accessible base of D. – Alexandre C. Dec 26 '10 at 00:35
  • Doesn't work: http://coliru.stacked-crooked.com/view?id=f4599b11c9f593a9790951a4b0fb36d4-50d9cfc8a1d350e7409e81e87c2653ba – rubenvb Apr 20 '13 at 15:31
  • In C++11, this template is now available as `std::is_base_of` in header ``. The `static_assert()` function is also built into C++11, and like the example above, it requires a second argument that defines an error message. – Fred Schleifer Nov 11 '17 at 02:45
0

What you want is something that uses SFINAE rules to make a template that will generate an error in the case that would normally be preferred, but can expand in another way as well. I believe that boost may already have a template that does just that already.

Someone else gave you some code. I'm leaving this answer because it explains how the code works.

Omnifarious
  • 54,333
  • 19
  • 131
  • 194