Неявное преобразование в явные bool-типы для сортировки контейнеров?

я играю с новым explicit для cast-операторов. Если вы пишете что-то вроде

struct Data {
    explicit operator string(); 
};

невозможно случайно преобразовать Data до string. Тип данных darget bool является исключением: в некоторых случаях неявное преобразование разрешено, даже если оно отмечено explicit -- контекстуальные преобразования. Таким образом, вы можете использовать эти типы данных в элементе if(...) например:

struct Ok {
    explicit operator bool(); // allowed in if(...) anyway
};

в пункте "25.4.(2) Сортировка и связанные с ней операции" кажется, позволяет это для Compare функтор из стандартные контейнеры как set как хорошо. Но мои попытки с GCC-4.7.0 терпят неудачу, и я уверен, что это мое неправильное понимание или ошибка в gcc?

#include <set>

struct YesNo { // Return value type of Comperator
    int val_;
    explicit YesNo(int y) : val_{y} {}
    /* explicit */ operator bool() { return val_!=0; }
};

static const YesNo yes{1};
static const YesNo no{0};

struct LessYesNo {  // Comperator with special return values
    YesNo operator()(int a, int b) const {
        return a<b ? yes : no;
    }
};

int main() {
    std::set<int,LessYesNo> data {2,3,4,1,2};
}

без explicit до operator bool() пример компилируется. И мое понимание "25.4.(2) " заключается в том, что это также должно компилироваться С в явные.

я понимаю Std правильно что за set и explicit bool преобразования должны работать? и может быть, это ошибка в gcc, или я понял что-то не так?

2 ответов


мое чтение стандарта немного отличается - раздел 25.4 касается алгоритмов сортировки, а не отсортированных контейнеров; контекст, установленный в 25.4.(1) означает, что свойство объекта сравнения указано в разделе 25.4.(2) применяется к алгоритмам в 25.4, а не к отсортированным контейнерам

1 Все операции в 25.4 имеют две версии: одна, которая принимает объект функции типа Compare и тот, который использует оператор.

2 Сравнивать функция тип объекта (20.8). Возвращаемое значение операция вызова функции, применяемая к объекту типа Compare, когда контекстуально преобразуется в bool (4), дает значение true, если первый аргумент звонка меньше второго, и false в противном случае. Сравнить comp используется для алгоритмов, предполагающих отношение упорядочения. Это предполагается, что comp не будет применять любую непостоянную функцию через разыменованный итератор.

Я не знаю, является ли ваш пример должен работать или нет, но я не думаю, что раздел 25.4 применимо здесь.

быстрый тест с вектором и std:: sort works:

#include <list>
#include <algorithm>

struct YesNo { // Return value type of Comperator
    int val_;
    explicit YesNo(int y) : val_{y} {}
    explicit operator bool() { return val_!=0; }
};

static const YesNo yes{1};
static const YesNo no{0};

struct LessYesNo {  // Comperator with special return values
    YesNo operator()(int a, int b) const {
        return a<b ? yes : no;
    }
};

int main() {
    std::vector<int> data {2,3,4,1,2};
    std::sort(std::begin(data), std::end(data), LessYesNo());
}

изменить:

параметр сравнения ассоциативного контейнера определяется в терминах secion 25.4:

1 ассоциативные контейнеры обеспечивают быстрый поиск данных, основанных на ключах. Библиотека предоставляет четыре основных вида ассоциативных контейнеров: set, multiset, map и multimap.

2 каждый ассоциативный контейнер параметризуется по ключу, и отношение упорядочения сравнивает это индуцирует строгий слабый порядок (25.4) на элементах ключа. Кроме того, map и multimap связывают произвольный тип T с ключом. Объект типа Compare называется объектом сравнения контейнера.

и 23. не имеет никаких других условий для типа сравнения, насколько я могу видеть, поэтому кажется разумным предположить, что тип, удовлетворяющий ограничениям 25.4, в равной степени применимо.


правильно ли я понял Std, что для set также должны работать явные преобразования bool?

это своего рода серая зона спецификации. Возвращаемое значение из функции сравнения должно быть "конвертируемым в bool". Но что это значит в свете explicit operator bool() непонятно.

например, можно написать std::setсравнение использования как это:

CompFunc functor;
if(functor(input, currVal))
  ...

или можно сделать это:

CompFunc functor;
bool test = functor(input, currVal);
if(test)
  ...

оба этих формально законно в C++11? Без понятия. Очевидно, что второй терпит неудачу, если operator bool() is explicit.

Я посмотрел на определение std::shared_ptr и explicit operator bool() как хорошо. Он также говорит, что std::shared_ptr является "конвертируемым в bool" в пункте 2 раздела 20.7.2.2.

поэтому я предполагаю, что вторая версия должны будет осуществляться следующим образом:

CompFunc functor;
bool test = static_cast<bool>(functor(input, currVal));
if(test)
  ...

тот факт, что это не явно указано в любом месте спецификации означает, что он должен быть подан как отчет о дефекте. Но он, вероятно, также должен быть подан как ошибка GCC/libstdc++.

лично я, чтобы быть в безопасности, я бы не полагался на это.


О Контекстном Преобразовании

в пункте 3 раздела 4 говорится:

выражение e, появляющееся в таком контексте, считается контекстуально преобразованным в bool и хорошо сформировано, если и только если объявление bool t (e); хорошо сформирован, для некоторой изобретенной временной переменной t

так операции, "контекстуально конвертируемых в bool" означает, что explicit operator bool() будет работать. С std::set"S" Compare " функтор должен подпадать под требования 25.4, и эти требования включают в себя "контекстно преобразованный в bool", он выглядит как ошибка GCC/libstdc++.

Я бы все равно избегал этого, когда вы можете помочь.