Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

boost::is_same with templated base class

I'm puzzled by the following problem. I want to write some trait struct in order to test if a certain class is derived from another. This can be solved with boost::is_base_of<>. However, the base class I want to test against has a free undefined template parameter.

Here is some code example:

template<typename T> class Base {};

class IntDeriv : Base<int> {};

class Foo {};

template< class TestClass >
struct is_derived_from_Base {
   // how to create something that does the following and forces the compiler to deduce T
   static const bool value = boost::is_base_of< Base<T> , TestClass >::value;
};

int main() {
    cout << is_derived_from_Base<Foo> << endl;         // should print 0
    cout << is_derived_from_Base<IntDeriv> << endl;    // should print 1
}

The problem is how to deduce T for Base<T> inside is_base_of. Is this possible at all? I smell some enable_if but I'm not sure how to put it together.

like image 493
André Bergner Avatar asked Jan 24 '26 00:01

André Bergner


1 Answers

What you want is possible. The trick used is possible in C++03, but as you didn't specify I will give you the C++11 version (using decltype, not available in C++03):

template<class TestClass>
struct is_derived_from_Base
{
    template<typename T>
    static std::true_type inherited(Base<T>*);
    static std::false_type inherited(void*);

    static const bool value = decltype(inherited(new TestClass()))::value;
};

You can see a live version here.

So, how does it works ?

When the struct is instantiated and value is needed, the compiler will get the return type of inherited(new TestClass()). This will call the appropriate function: if TestClass inherits Base<T>, then TestClass* (returned by new) is castable to Base<T>*, T being automatically deduced by the compiler. The return type is std::true_type. If TestClass does not inherits Base<T>, then the other overload is choosen, and the return type is std::false_type. The rest is straightforward: std::true_type::value = true and std::false_type::value = false.

There are still some corner cases:

  • Using private inheritance results in a compile error. I do not know how to solve it, because I don't know the answer: if A privately inherits B, is A derived from B or not ? (in general, private inheritance is considered as an implementation inheritance). Also note that in this case, A* a = new B(); will not compile.
  • Using a private constructor prevents the previously explained trick from working correctly. It will result in a compile-time error. Since this defeats the whole point of this method, you will have to find another way for such classes.

Note you have to use it the following way: is_derived_from_Base<Foo>::value, not as you've written (is_derived_from_Base<Foo>).

like image 139
Synxis Avatar answered Jan 26 '26 16:01

Synxis



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!