2015-07-29 16 views
1

Я использую BOOST_STRONG_TYPEDEF для определения сильных типов типов POD. Например, я хочу определить новый тип от int. Однако, если я попытаюсь сравнить свой новый тип с чем-то, что не int (например, unsigned int, size_t), я получаю «Использование перегруженного оператора» < «неоднозначный» компилятор ошибок.BOOST_STRONG_TYPEDEF и перегруженные операторы связи

Например:

#include <boost/serialization/strong_typedef.hpp> 

BOOST_STRONG_TYPEDEF(int, Foo); 

int main(int argc, const char * argv[]) { 

    Foo f(10); 

    unsigned int j = 11; 
    bool result = j < f; // Error 

    size_t s = 100; 
    result = s < f;   // Error 

    int h = 101; 
    result = h < f;  // ok 

    return 0; 
} 

я могу исправить эти ошибки путем реализации конкретных реляционных операторов для конкретных типов. например .:

bool operator<(const size_t& y, const Foo& x) { 
    return y < x.t; 
} 

С BOOST_STRONG_TYPEDEF предоставляет операторы преобразования из Foo в int, я ожидал бы (unsigned int) < (Foo) компилировать вниз к тому же, как (unsigned int) < (int), но я не думаю.

Мой вопрос: есть ли способ избежать внедрения каждого оператора для каждого типа, с которым я хочу сравнить?

ответ

2

С BOOST_STRONG_TYPEDEF предоставляет операторы преобразования из Foo в int, я ожидал бы (unsigned int) < (Foo) компилировать вниз к тому же, как (unsigned int) < (int), но я не думаю.

BOOST_STRONG_TYPEDEF макрос определяет struct Foo, который наследует от связки различных классов операторов, один из которых будет определять:

friend bool operator<(const int&, const Foo&); //(1) 

И, конечно, есть все встроенные команды, которые сравнивают числа:

bool operator<(T, U); // (2), implicit 

Для всех интегральных типов I у нас есть несколько жизнеспособных кандидатов для I{} < Foo{}. Мы могли бы конвертировать I в int и звонить по номеру (1), или мы могли бы конвертировать Foo в int и звонить по номеру (2). В зависимости от I, результат:

  • I является int: (1) точное совпадение, и все операторы включают встроенные преобразования, так (1) однозначно предпочтительнее.
  • I имеет нижний ранг, чем int (например, char): интегральное продвижение (до int) имеет лучший ранг, чем конверсии (Foo в int), поэтому (1) однозначно предпочтительным.
  • I имеет высшее ранг, чем int (например, size_t и unsigned int в вашем примере): (1) Теперь включает в себя целое преобразование (size_t в int не является продвижение), и целые преобразования имеют ранг Конверсия, тот же ранг в виде определяемое пользователем преобразование.Таким образом, и у (1), и у (2) будет одно точное соответствие и одно преобразование. Поскольку ни один из них не лучше другого, он неоднозначен.

Мой вопрос: Есть ли способ избежать реализации каждого оператора для каждого типа я хочу сравнить?

Нет, нет. Тем не менее, вы можете реализовать каждый оператор для каждого типа всего за один раз с помощью шаблонов. Например, мы можем разрешить все неоднозначности < с:

template <typename T> 
bool operator<(const T& t, const Foo& f) 
{ 
    return t < static_cast<int>(f); 
} 

Для целочисленных типов с рангом, равным int, (1) все еще предпочтительнее. Но для всех других интегральных типов шаблон будет точным совпадением, тогда как встроенные и (1) связаны с некоторой последовательностью преобразований, поэтому это было бы предпочтительнее - это было бы продвигаться вперед до двусмысленного встроенного.

+0

Очень информативный ответ, спасибо. Есть ли причина предпочесть static_cast в функции шаблона по прямому доступу к переменной члена Foo? – Tyson

Смежные вопросы