开发者

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

In a comparison opera开发者_StackOverflow社区tor:

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.


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.)


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?


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;
}


If concepts 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.


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


I must admit, I don't see the motivation behind this, particularly 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 a warning, both template parameter types must be capable of being parameters to the Manager template, and those types must have private members (I assume p1 & p2 should be m1 & m2) called internal_field. Given those constraints, what is the chance that this template function can be called by accident on the wrong type(s)?

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜