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.
Solution 1:
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.)
Solution 2:
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?
Solution 3:
In this post I'm considering the problem of checking if a type exactly matches another, it's not exactly what is asked for, but it is simpler and I hope it can help to understand the applied template tricks.
As done in boost, template specializations can be adopted for that task, in fact you can define a template struct containing operations on a given type, and use nested template structs for that operations. In our case:
// Working on a specific type:
template <typename T1>
struct is_type {
// For all types T2!=T1 produce false:
template <typename T2>
struct same_of { static const bool value = false; };
// Specialization for type T2==T1 producing true:
template <>
struct same_of<T1> { static const bool value = true; };
};
Defining a macro allows to use it easily:
#define is_type_same(T1,T2) (is_type<T1>::same_of<T2>::value)
as follows:
template<class R1, class R2>
bool operator==(Manager<R1> m1, Manager<R2> m2) {
return is_type_same(R1,R2) && m1.internal_field == m2.internal_field;
}
Solution 4:
If concept
s would have been included in C++0x you might have been able to use them with a compiler that implement them (like gcc).
As it's not the case, the only alternative currently available to do what you want seem to be the Boost Concept Check library.
Solution 5:
template<class T, class B> struct Derived_from {
static void constraints(T* p) { B* pb = p; }
Derived_from() { void(*p)(T*) = constraints; }
};
template<class R2, class R1>
bool test(R1& r1) {
Derived_from<R1,R2>(); // accept if R1 is derived from R2
return false;
}
class Base {
public:
virtual ~Base() { }
};
class Derived : public Base {
};
class Other {
};
int _tmain(int argc, _TCHAR* argv[])
{
Derived d;
Other o;
test<Base>(d); // OK
test<Base>(o); // Fails in VC++ 2005
return 0;
}
Credits go to http://www2.research.att.com/~bs/bs_faq2.html#constraints