Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Implement a template function that takes two classes as template parameters and returns true if they are inherited

Below is the code i have come across that actually does the job of std::is_base_of function in C++11 or boost::is_base_of.

Below helper function does the same:

template<typename D, typename B>
class IsDerivedFromHelper
{
   class No { };
   class Yes { No no[3]; };

   static Yes Test( B* );
   static No Test( ... );
public:
    enum { Is = sizeof(Test(static_cast<D*>(0))) == sizeof(Yes) };

};


template <class C, class P> 
bool IsDerivedFrom() {
 return IsDerivedFromHelper<C, P>::Is;
}

Can someone explain what excatly the enum Is does?

What are static Yes Test and static No Test? Are they function calls ?

like image 223
LearningCpp Avatar asked Sep 13 '16 09:09

LearningCpp


People also ask

What is template explain function templates and class templates with example?

Templates in c++ is defined as a blueprint or formula for creating a generic class or a function. To simply put, you can create a single function or single class to work with different data types using templates. C++ template is also known as generic functions or classes which is a very powerful feature in C++.

What is class template and function template in C++?

A template allows us to create a family of classes or family of functions to handle different data types. Template classes and functions eliminate the code duplication of different data types and thus makes the development easier and faster. Multiple parameters can be used in both class and function template.

Can a template be a template parameter?

Templates can be template parameters. In this case, they are called template parameters. The container adaptors std::stack, std::queue, and std::priority_queue use per default a std::deque to hold their arguments, but you can use a different container.


1 Answers

class No { }; - defines a class, which will have an undefined size, which won't be zero (mandated by the standard)

class Yes { No no[3]; }; - defines another class, Yes which will be at least 3 times as big as a No. So they are guaranteed to be different sizes.

static Yes Test( B* ); - declare a function which returns a Yes, but don't give it a definition (we don't need one). It will match any pointer argument which is pointing to an object derived from B.

static No Test( ... ); - declare a function which returns a No (smaller, remember?). It's an overload which will be selected if the more specific one (above) cannot be satisfied. It accepts any argument (but the other version will be selected by overload resolution in preference if the argument is derived from B).

sizeof(Test(static_cast<D*>(0))) deduces the size of the object returned by Test when passes a pointer to a D. If D is derived from B, it will be a Yes, otherwise it will be a No.

Because the 'call' is made in a non-deduced context, it is not evaluated (called), just selected and return type deduced.

The rest is probably self-explanatory. turns out it wasn't :)

So this all gets put together here:

enum { Is = sizeof(Test(static_cast<D*>(0))) == sizeof(Yes) };

What this is doing in a nutshell, is saying:

"declare a constant called Is, which will be true if the result of calling Test with a D* is a type that happens to be the same size as a Yes. And it will be false if the result of the call happens to be a type which is a different size. Because of the two overloads, above, when D is a B, or anything derived from it, Test(D*) will select the Yes version, which will return a Yes, which is obviously the same size as a Yes. If this overload is not selected, the more permissive (but lower priority) one will be. That one returns a No, which obviously won't be the same size as a Yes (by definition)."

Why is Test(...) 'lower priority' than Test(B*) (in terms of overload resolution)? Because it just is. The standard defines it to be.

Finally:

template <class C, class P> 
bool IsDerivedFrom() {
 return IsDerivedFromHelper<C, P>::Is;
}

This creates a function which will return the result of the above test for any two class types, C and P. This it will return true if P is derived from a C and false otherwise.

like image 100
Richard Hodges Avatar answered Oct 22 '22 08:10

Richard Hodges