Я ожидал, что boost::function_output_iterator является std::output_iterator, но на удивление это не так:
#include <boost/iterator/function_output_iterator.hpp>
template<std::output_iterator<int> IntOutIter>
void
f(IntOutIter outputIterator){}
int main(int argc, char const *argv[])
{
f(boost::make_function_output_iterator([](int i){}));
return 0;
}
(Обратите внимание, синтаксис template<std::output_iterator<int> IntOutIter> из Как объявить функцию шаблона, которая принимает выходной итератор T?)
clang++ -std=c++20 function-output-iterator.cpp ошибки с:
error: no matching function for call to 'f'
note: candidate template ignored: constraints not satisfied [with IntOutIter = function_output_iterator<(lambda at function-output-iterator.cpp:11:42)>]
note: because 'std::output_iterator<boost::iterators::function_output_iterator<(lambda at function-output-iterator.cpp:11:42)>, int>' evaluated to false
note: because 'boost::iterators::function_output_iterator<(lambda at function-output-iterator.cpp:11:42)>' does not satisfy 'input_or_output_iterator'
note: because 'boost::iterators::function_output_iterator<(lambda at function-output-iterator.cpp:11:42)>' does not satisfy 'weakly_incrementable'
note: because 'iter_difference_t<function_output_iterator<(lambda at function-output-iterator.cpp:11:42)>>' (aka 'void') does not satisfy '__is_signed_integer_like'
note: because 'void' does not satisfy 'signed_integral'
note: because 'void' does not satisfy 'integral'
note: because 'is_integral_v<void>' evaluated to false
note: and 'void' does not satisfy '__is_signed_int128'
note: because 'same_as<void, __int128>' evaluated to false
note: because '__detail::__same_as<void, __int128>' evaluated to false
note: because 'std::is_same_v<void, __int128>' evaluated to false
note: and 'same_as<void, __max_diff_type>' evaluated to false
note: because '__detail::__same_as<void, std::ranges::__detail::__max_diff_type>' evaluated to false
note: because 'std::is_same_v<void, std::ranges::__detail::__max_diff_type>' evaluated to false
1 error generated.
Подозреваю, что это потому, что boost::function_output_iteratorзаявляет
typedef void difference_type;
Но стандарт гласит, что это должно быть integral, а не void:
output_iterator, нужно быть weakly_incrementable (через input_or_output_iterator)std::iter_difference_t<T> = ...::difference_type (связывает iter_difference_t и difference_type в коде Boost)requires is-signed-integer-like<iter_difference_t<I>> для weakly_incrementableОбщие рекомендации — реализовать difference_type как ptrdiff_t, а не void:
Я знаю, что это компилируется:
-template<std::output_iterator<int> IntOutIter>
+template<IntOutIter>
void
f(IntOutIter outputIterator){}
Но это лишает C++ преимущества concepts: ограничение переменных универсального типа для улучшения сообщений об ошибках и указания, какие операции они должны поддерживать.
Итак, разве function_output_iterator не должно быть output_iterator?
Далее, boost docs утверждает:
function_output_iterator— это модель концепцийWritableиIncrementableIterator.`
Но инкрементируемый требует weakly_incrementable, образцом которого он явно не является!
Итак, что дает?
boost::function_output_iterator реализовано неправильно?
Или я не должен иметь возможность использовать его как output_iterator, а документы по повышению неверны?
Я думаю, что @ChristianStieber это делает, и это заслуживает ответа.
Эта конкретная часть Boost была написана двадцать четыре года назад и с тех пор почти не менялась.





Это всего лишь предположение — я не являюсь автором этой конкретной библиотеки повышения (ну, я не являюсь автором НИКАКОЙ библиотеки повышения...) и не связан с повышением больше, чем любой другой пользователь.
Дата на странице документации по повышению, на которую вы ссылаетесь, относится к 2006 году, что позволяет предположить, что она довольно старая и предшествует C++20 достаточно давно, чтобы предположить, что на момент создания библиотеки они все еще работали над C++11.
Boost обычно много говорит о концепциях в своей документации, но они (обычно) не ссылаются на концепции C++20. Они используют этот термин для обозначения таблицы свойств типов, например здесь. Это похоже на концепцию C++20, но без поддержки компилятора.
Повышает неформальные концепции и концепции, найденные в STL, могут даже иметь одинаковые имена, но это не значит, что они на 100% одно и то же. Возможно, автор этой библиотеки не нашел времени привести ее в соответствие с STL. Возможно, у них есть проблемы с совместимостью существующего кода. Или, может быть, они больше ничего не делают с этой библиотекой.
Мы все думаем, что сделать вещи совместимыми с STL — отличная идея, но реальную работу делаем не мы :-)
Угу, я вижу. Я не ожидал, что это повысит «концепции» != «концепции» C++. Я думаю, было бы очень полезно, если бы в документации Boost была хотя бы ссылка на страницу , на которую вы ссылались , чтобы можно было сказать, что это разные концепции. Я не знал, насколько «устаревшим» является boost в некоторых аспектах — мой опыт до сих пор сводился к тому, что Boost опережает C++ STL в отношении новых идей и что он обновляется, когда они превращаются в ядро C++. Очевидно, что это не всегда так. Спасибо за ответ!
Непосредственный последующий вопрос: существует ли стандартная современная альтернатива boost:function_output_iterator, которая работает с концепцией std::output_iterator?
@nh2 в эпоху std::ranges они стали известны как источники/приемники и не так популярны. Вы можете прочитать дополнительную информацию и, возможно, полезные советы thephd.dev/output-ranges
Это всего лишь предположение, но вы смотрели на дату документов по повышению, на которые вы ссылались? Это из 2006 года... Когда boost говорит о «концепциях», они обычно (никогда?) не имеют в виду C++20: для них «концепция» — это просто таблица требований, как boost. org/doc/libs/1_85_0/libs/iterator/doc/…. Возможно, они не удосужились привести это в соответствие с тем, что фактически было превращено в стандарт C++...