Почему этот бросок нужен?
template<typename InputIterator, typename Predicate>
inline InputIterator
find_if(InputIterator first, InputIterator last, Predicate pred, input_iterator_tag)
{
while (first != last && !bool(pred(*first)))
++first;
return first;
}
Я столкнулся с этим фрагментом в исходном коде реализации стандартной библиотеки С++, поставляемой с GCC 4.7.0. Это специализация find_if
для входного итератора. Я очистил ведущие символы подчеркивания, чтобы сделать его более читаемым.
Почему они использовали приведение bool
к предикату?
Ответы
Ответ 1
Причина в том, что просто запись !pred(*first)
может привести к вызову перегруженного operator!
, а не к вызову explicit operator bool
.
Интересно, что эта мера принималась за pred
, но перегруженный operator&&
может быть выбран в предоставленной реализации. first != last
необходимо будет изменить на bool(first != last)
, чтобы предотвратить эту перегрузку.
Ответ 2
Стандарт требует только того, чтобы предикат можно было использовать в
контекст, где он может конвертироваться в bool
. Предположительно,
объект "предикат" может иметь функцию operator bool
который сделал правильную вещь, и функцию operator!
, которая
что-то совершенно не связанное. (Конечно, это было бы ужасно
дизайн, но стандарт требует, чтобы библиотека работала как
указанному, независимо от того, насколько плохим является код пользователя.) Так что g++
преобразуется в bool
, а затем использует !
в результате этого
преобразование (где может применяться только оператор сборки).
Ответ 3
В стандарте С++ написано относительно предиката, что
Иными словами, если алгоритм принимает Predicate pred в качестве аргумента и сначала как аргумент итератора, он должен корректно работать в create pred (* first), контекстно преобразованный в bool
Слова "контекстно преобразованные в bool" означают, что если даже класс определяет функцию преобразования, которая преобразует объект класса в bool как явный оператор, он применяется. Рассмотрим пример контекстного преобразования в bool
#include <iostream>
struct A
{
explicit operator bool () const { return true; }
};
int main()
{
if ( A() )
{
std::cout << "Here is a contextual conversion to bool" << std::endl;
}
}
Итак, в контексте стандартной цитаты С++ я не вижу смысла в написании выражения
first != last && !bool( pred(*first ) )
Достаточно написать
first != last && !pred(*first )
Здесь pred преобразуется в контекст в bool.