Неявное преобразование в явные типы bool для сортировки контейнеров? - PullRequest
10 голосов
/ 04 ноября 2011

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

struct Data {
    explicit operator string(); 
};

Невозможно случайно конвертировать Data в string. Тип данных цели 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 ]

3 голосов
/ 04 ноября 2011

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

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

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

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

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

#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());
}

Редактировать:

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

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

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

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

2 голосов
/ 04 ноября 2011

Правильно ли я понял 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() равен explicit.

Я посмотрел на определение std::shared_ptr, и у него также есть explicit operator bool().В нем также говорится, что std::shared_ptr «конвертируется в bool», в разделе 20.7.2.2, параграф 2.

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

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

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

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


В контексте контекстного преобразования

Раздел 4, параграф 3 гласит:

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

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

Я бы по-прежнему избегал этогоэто когда ты можешь помочь, хотя.

...