Неявное преобразование в явные типы bool для сортировки контейнеров?
Я играю с новым explicit
для операторов-литов. Если вы напишете что-то вроде
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, или я понял что-то не так?
Ответы
Ответ 1
Мое чтение стандарта немного отличается -
раздел 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 применим здесь.
Быстрый тест с использованием функции vector и 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());
}
Edit:
Ассоциативный контейнер. Параметр сравнения определяется в терминах secion 25.4:
1 Ассоциативные контейнеры обеспечивают быстрый поиск данных на основе ключей. Библиотека предоставляет четыре основных типа ассоциативных контейнеров: набор, мультимножество, карту и мультимап.
2 Каждый ассоциативный контейнер параметризуется по ключу и отношениям упорядочения. Сравните это индуцирует строгое слабое упорядочение (25.4) на элементах Клю. Кроме того, map и multimap связывают произвольный тип T с ключом. Объект типа Compare называется объектом сравнения контейнера.
и 23. не имеет других условий для типа Compare, насколько я могу видеть, поэтому представляется разумным предположить, что тип, удовлетворяющий ограничениям 25.4, одинаково применим.
Ответ 2
Я правильно понял Std, что для set также должны работать явные преобразования bool?
Это своего рода серая область спецификации. Возвращаемое значение из функции сравнения требуется для "конвертируемого в bool". Но что это означает в свете explicit operator bool()
, неясно.
Например, можно было бы использовать std::set
использование сравнения как это:
CompFunc functor;
if(functor(input, currVal))
...
Или это можно сделать:
CompFunc functor;
bool test = functor(input, currVal);
if(test)
...
Являются ли оба из них технически законными в С++ 11? Без понятия. Очевидно, что вторая неудачна, если operator bool()
explicit
.
Я посмотрел на определение std::shared_ptr
, и он также имеет explicit operator bool()
. В нем также говорится, что std::shared_ptr
является "конвертируемым в bool", в пункте 20.7.2.2 раздела.
Итак, я предполагаю, что вторая версия должна быть реализована следующим образом:
CompFunc functor;
bool test = static_cast<bool>(functor(input, currVal));
if(test)
...
Тот факт, что он явно не указан нигде в спецификации, означает, что он должен быть подан как отчет о дефектах. Но он также должен быть подан как ошибка GCC/libstdС++.
Лично, чтобы быть в безопасности, я не стал бы на него полагаться.
По контекстуальному преобразованию
В пункте 4 раздела 4 говорится:
Выражение e, появляющееся в таком контексте, называется контекстно преобразованным в bool и хорошо сформировано тогда и только тогда, когда декларация bool t (e); хорошо сформирована, для некоторой изобретенной временной переменной t
Таким образом, операции, которые "контекстно конвертируются в bool", означают, что explicit operator bool()
будет работать. Поскольку std::set
"Сравнить" функтор должен подпадать под требования 25.4, и эти требования включают "контекстно преобразованный в bool", он выглядит как ошибка GCC/libstdС++.
Я бы все же избегал делать это, когда вы можете помочь.