В операторе сравнения:
template<class R1, class R2>
bool operator==(Manager<R1> m1, Manager<R2> m2) {
return m1.internal_field == m2.internal_field;
}
Есть ли какой-либо способ, которым я мог осуществить это, R1 и R2 должны иметь отношение подтипа или супертип? Таким образом, я хотел бы позволить или R1 быть полученным из R2 или R2, который будет получен из R1, но запретил бы сравнение, если R1 и R2 являются несвязанными типами.
Требуемая вам черта может выглядеть так:
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);
};
Тогда вам просто понадобится какое-то статическое утверждение:
// really basic
template <bool>
struct static_assert;
template <>
struct static_assert<true> {}; // only true is defined
#define STATIC_ASSERT(x) static_assert<(x)>()
Затем соедините два вместе:
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;
}
Если одно не является производным от другого, функция не будет компилироваться. (Ваша ошибка будет похожа на « static_assert
not defined», и она будет указывать на эту строку.)
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;
}
Кредиты идут на http://www2.research.att.com/~bs/bs_faq2.html#constraints
Если бы концепт
s был бы включен в C ++ 0x, вы могли бы использовать их с компилятором, который их реализует (например, gcc).
Поскольку это не так, единственная доступная альтернатива для выполнения того, что вы хотите, - это библиотека Boost Concept Check .
Вы можно использовать типовые черты boost ( is_base_of ) и 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;
}
С другой стороны, почему использование operator == имеет большее значение с типами того же дерева наследования? Разве для достижения значимых результатов не пришлось бы использовать двойную отправку?
Должен признать, я не вижу мотивации, стоящей за этим, особенно если это требует написания большого количества вспомогательного кода. Для вашего оператора:
template<class R1, class R2>
bool operator==(Manager<R1> m1, Manager<R2> m2) {
return p1.internal_field == p2.internal_field;
}
для компиляции без предупреждения оба типа параметров шаблона должны иметь возможность быть параметрами для шаблона Manager, и эти типы должны иметь закрытые члены (я предполагаю, что p1 и p2 должны быть m1 и m2), называемые internal_field. Учитывая эти ограничения, какова вероятность того, что эта функция шаблона может быть вызвана случайно для неправильного типа (ов)?