Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++: How to require that one template type is derived from the other

In a comparison operator:

template<class R1, class R2>
bool operator==(Manager<R1> m1, Manager<R2> m2) {
    return m1.internal_field == m2.internal_field;
}

Is there any way I could enforce that R1 and R2 must have a supertype or subtype relation? That is, I'd like to allow either R1 to be derived from R2, or R2 to be derived from R1, but disallow the comparison if R1 and R2 are unrelated types.

like image 226
Will Avatar asked Apr 13 '10 17:04

Will


People also ask

Can a template base class derived?

It is possible to inherit from a template class. All the usual rules for inheritance and polymorphism apply. If we want the new, derived class to be generic it should also be a template class; and pass its template parameter along to the base class.

Can you have templates with two or more generic arguments?

CLASS TEMPLATE WITH MULTIPLE PARAMETERSWe can use more than one generic data type in a class template, and each generic data type is separated by the comma.

What is the rule of compiler by templates?

The compiler usually instantiates members of template classes independently of other members, so that the compiler instantiates only members that are used within the program. Methods written solely for use through a debugger will therefore not normally be instantiated.

What is a templated function C++?

Function templates. Function templates are special functions that can operate with generic types. This allows us to create a function template whose functionality can be adapted to more than one type or class without repeating the entire code for each type. In C++ this can be achieved using template parameters.


2 Answers

A trait you want might look like this:

template <typename B, typename D>
struct is_base_of // check if B is a base of D
{
    typedef char yes[1];
    typedef char no[2];

    static yes& test(B*);
    static no& test(...);

    static D* get(void);

    static const bool value = sizeof(test(get()) == sizeof(yes);
};

Then you just need a static assert of some sort:

// really basic
template <bool>
struct static_assert;

template <>
struct static_assert<true> {}; // only true is defined

#define STATIC_ASSERT(x) static_assert<(x)>()

Then put the two together:

template<class R1, class R2>
bool operator==(Manager<R1> m1, Manager<R2> m2)
{
    STATIC_ASSERT(is_base_of<R1, R2>::value || is_base_of<R2, R1>::value);

    return p1.internal_field == p2.internal_field;
}

If one does not derive from the other, the function will not compile. (Your error will be similar to "static_assert<false> not defined", and it will point to that line.)

like image 169
GManNickG Avatar answered Oct 05 '22 19:10

GManNickG


You can use boost's typetraits (is_base_of), and boost's enable_if.

#include <boost/type_traits.hpp>
#include <boost/utility/enable_if.hpp>

template <class R1, class R2>
struct has_derived_base_relationship :
    boost::integral_constant<
        bool, boost::is_base_of<R1, R2>::value || boost::is_base_of<R2, R1>::value 
    >
{};

template<class R1, class R2>
typename boost::enable_if<has_derived_base_relationship<R1, R2>, bool>::type 
operator==(Manager<R1> m1, Manager<R2> m2) {
    return p1.internal_field == p2.internal_field;
}

On the other hand, why would operator== usage have more value with types of the same inheritance tree? Wouldn't it have to use double dispatch to achieve meaningful results?

like image 45
UncleBens Avatar answered Oct 05 '22 18:10

UncleBens