2017-02-14 30 views
0

По boost documentation - правильное использование повышающего :: операторов вывести из него:Возможно ли наследовать от boost :: операторов, но все равно использовать его?

class A : boost::operators<A> 
{ 
public: 
    bool operator < (const A&) const { return false; } 
}; 

Теперь я могу использовать > и <= и >=, потому что все эти операторы могут быть реализованы с помощью < см фрагмент кода от повышения:

template <class T, class B = operators_detail::empty_base<T> > 
struct less_than_comparable1 : B 
{ 
    friend bool operator>(const T& x, const T& y) { return y < x; } 
    friend bool operator<=(const T& x, const T& y) { return !static_cast<bool>(y < x); } 
    friend bool operator>=(const T& x, const T& y) { return !static_cast<bool>(x < y); } 
}; 

И наконец less_than_comparable1 это один из boost::operators базового класса.

ПРОБЛЕМА: Но добавление такого наследования не всегда удобно. Например. это наследование означает, что я должен добавить конструктор (ы) для некоторых структур, в противном случае весь старый код, например A{1} остановки компиляции:

struct A : boost::operators<A> 
{ 
    A() = default; 
    A(int a, int b = 0) : a(a), b(b) {} 
    int a; 
    int b; 
}; 
bool operator < (const A&, const A&); 

Я попробовал несколько способов: внутренний класс, статические члены boost::operators<A> но мне кажется, что только наследование работает.


Я принимаю ответ, который показывает способ использования boost :: операторов без наследования.
Я также могу принять ответ, который объясняет, почему это наследование необходимо.


Хорошо, давайте упростить немного этот пример, почему мне нужно наследование в этом самом примере ниже, чтобы получить operator > от operator <?

template <typename A> 
struct GtOperator 
{ 
    friend bool operator > (const A& l, const A& r) 
    { 
     return r < l; 
    } 
}; 

struct A : private GtOperator<A> 
{ 
    bool operator < (const A&) const 
    { 
     return false; 
    } 
}; 

int main() { 
    if (A{} > A{}) 
    { 
     return -1; 
    } 
} 

Ничто другое не работает, например. этот способ не работает:

struct A 
{ 
    GtOperator<A> dummy; 

    bool operator < (const A&) const 
    { 
     return false; 
    } 
}; 
+0

Либо запишите его вручную, либо напишите макрос препроцессора. (Есть только шесть операторов, и вы все равно должны писать 'operator>'. Часто может быть полезно писать 'operator =='. –

+0

@MartinBonner 'boost :: operator' предлагает гораздо больше, чем эти 3. Мне просто нравится знать, как использовать его без наследования, если это возможно. Или знать, почему требуется наследование – PiotrNycz

+0

@jaggedSpire Нет никакого добавления к дочернему классу в boost :: operator. Есть только друзья-операторы, подобные этим из 'less_than_comparable1' - без downcasting. Вот почему я спрашиваю, зачем нужно наследование? – PiotrNycz

ответ

2

Можно не наследовать от boost::operators, но до сих пор его использовать?

Нет, в основном. Он предназначен для унаследованных. Причина, по которой он работает, заключается в том, что зависящий от аргумента поиск будет искать только функции друзей и шаблоны функций в связанных классах ([basic.lookup.argdep]/4) - которые должны быть базовыми классами A и A. Если boost::operators<A> не является базовым классом A, его функции friend не будут найдены по имени.

Даже с новыми правилами инициализации агрегата в C++ 17, A{1,2} будет ломаться, потому что вам придется писать A{{},1,2}.

Ваш лучший выбор - это, вероятно, написать макрос, который функционирует как mixin, который эффективно выполняет ту же самую вещь. Таким образом, заказными являются:

#define LESS_THAN_COMPARABLE(T) \ 
friend bool operator>(const T& x, const T& y) { return y < x; } \ 
friend bool operator<=(const T& x, const T& y) { return !static_cast<bool>(y < x); } \ 
friend bool operator>=(const T& x, const T& y) { return !static_cast<bool>(x < y); } 

class A 
{ 
public: 
    bool operator < (const A&) const { return false; } 
    LESS_THAN_COMPARABLE(A) 
}; 

Да, это отстой. (Также они могут быть определены как функции, отличные от членов, просто отпустите friend и поместите вызов макроса вне класса).

Другая альтернатива, помимо добавления конструкторов и написания макросов, заключается в надежде, что <=> придет к осуществлению, а затем подождать несколько лет, чтобы иметь возможность использовать его.

+0

Я подозревал, что получаю такой ответ. Но я до сих пор не знаю, зачем здесь наследование? Почему такая конструкция не работает 'struct A {bool operator <(A) const; используя dummy = boosts :: operator ;}; '. В «классическом» CRTP есть downcast для класса параметров шаблона - в boost :: operator есть только функции друзей, а не downcasting вообще – PiotrNycz

+0

@PiotrNycz Добавлено это объяснение. – Barry

+0

Хорошо, я нашел параллель с вашим ответом на эту вики: https://en.wikipedia.org/wiki/Barton%E2%80%93Nackman_trick и http://www.open-std.org/jtc1/sc22/wg21 /docs/papers/1995/N0777.pdf. Таким образом, ответ ADL работает только для функций, вводимых как друзья базовым классам - вот трюк. – PiotrNycz