2015-11-09 3 views
5

Я видел, что выглядит как несогласованность в синтаксисах std :: lower_bound() и std :: upper_bound() (ну, тип-преобразование, действительно), и задавался вопросом, может ли кто-нибудь разъяснить, пожалуйста? По комментариям строка 2 не будет компилироваться, несмотря на очевидное сходство с строкой 1; Вы должны использовать форму, показанную на линии 3 (на GCC 4.7.3/убунту 64-битном, по крайней мере - это все, что я должен играть с)Требования к несогласованности верхнего и нижнего_ограничения

#include <set> 
#include <algorithm> 

using namespace std; 

class MyInt { 
    private: 
    int val; 
    public: 
    MyInt(int _val): val(_val) {} 
    bool operator<(const MyInt& other) const {return val < other.val;} 
}; 

int main() { 
    set<MyInt> s; 
    s.insert(1); // demonstrate implicit conversion works 
    s.insert(MyInt(2)); 
    s.insert(3); // one last one for the road 
    set<MyInt>::iterator itL = lower_bound(s.begin(), s.end(), 2); //LINE 1 
    // the line below will NOT compile 
    set<MyInt>::iterator itU = upper_bound(s.begin(), s.end(), 2); //LINE 2 
    // the line below WILL compile 
    set<MyInt>::iterator itU2 = upper_bound(s.begin(), s.end(), MyInt(2)); // LINE 3 
    return 0; 
} 
+0

То же поведение с g ++ 4.8.4 здесь. Это определенно ошибка g ++. –

ответ

5

Я не думаю, что это ошибка. Если вы посмотрите на (possible) implementation of std::upper_bound, сравнение сделано как

if (!(value < *it)) { ... } // upper_bound, implicit conversion `MyInt`->`int` doesn't work 

И потому, что operator< функция состоит MyInt (а не int, что не тип класса), код не компилируется, так как нет конверсии от MyInt до int. С другой стороны, в std::lower_bound, *it появляется на lhs сравнения, а value (типа int) может быть неявно преобразовано в MyInt при передаче MyInt::operator<.

if (*it < value) { ... } // lower_bound, implicit conversion `int`->`MyInt` works 

Это причина, почему это лучше реализовать операторы сравнения, как, не являющихся членами, так что вы не имеете этой асимметрии. Это также упоминается в статье Скотта Мейерса Effective C++ книга: Пункт 24: Объявлять функции, не являющиеся членами, когда преобразования типов должны применяться ко всем параметрам.

быстро и без исправления: определить MyInt::operator int(){return val;} для неявного преобразования MyInt в int. (EDIT: на самом деле не работает, неоднозначность). Какие работы устраняют необходимость неявного преобразования

set<MyInt>::iterator itU = upper_bound(s.begin(), s.end(), MyInt(2)); 

вместо этого.

+0

хороший копать там, спасибо! Интересно, что реализация STL (возможно) смешивает его интерфейс. Еще одна причина ненавидеть неявные преобразования типов – aho

+0

@aho Да, хорошая веская причина, отличный вопрос кстати. Вероятно, 'std :: upper_bound' может быть« исправлен », если мы выполним дополнительное преобразование из' value' в '* it' и сохраним его во временное, а затем используем последнее в сравнении. В этом случае поведение будет точно похоже на 'std :: lower_bound', и нет никакой цены для оплаты (вы все равно платите, если хотите, чтобы код был скомпилирован). – vsoftco

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