C ++: how to require one type of template to be derived from another

In the 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 to ensure that R1 and R2 are supertype or subtype related? That is, I would like to allow the derivation of R1 from R2 or R2, which should be obtained from R1, but to prohibit comparison if R1 and R2 are unrelated types.

+14
c ++ templates metaprogramming
Apr 13 '10 at 17:06
source share
6 answers

You can 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 some kind of static statement:

 // 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 them 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 fails from the other, the function will not compile. (Your error will be similar to " static_assert<false> not defined", and it will point to this line.)

+24
Apr 13 '10 at 17:20
source share

You can use boost typetraits ( is_base_of ) and boost 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 is using operator == more relevant with the types of a single inheritance tree? Wouldn't it be necessary to use double submission to achieve meaningful results?

+21
Apr 13 '10 at 17:21
source share

In this post, I consider the problem of checking whether the type matches exactly the other, this is not exactly what is required, but it is simpler, and I hope that this helps to understand the template tricks used.

As in boost, specialized templates can be used for this task, in fact you can define a template structure containing operations on this type and use nested template structures for these 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 makes it easy to use:

 #define is_type_same(T1,T2) (is_type<T1>::same_of<T2>::value) 

in the following way:

 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; } 
+3
Sep 11 '12 at 22:00
source share

If concept s would be included in C ++ 0x, you could use them with a compiler that implements them (e.g. gcc).

By no means, the only alternative currently available to do what you want is the Boost Concept Support Library .

+1
Apr 13 '10 at 17:11
source share
 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

+1
Apr 13 '10 at 17:42 on
source share

I have to admit that I see no motivation, especially if it requires writing shedloads of supporting code. For your operator:

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

to compile without warning, both types of template parameters must be capable of manager template parameters, and these types must have private members (I assume p1 and p2 must be m1 and m2) called internal_field. Given these limitations, what is the likelihood that this template function can be called accidentally on the wrong type (s)?

+1
Apr 13 '10 at 17:51
source share



All Articles