Я хочу объединить std::views::split
или std::views::lazy_split
с std::ranges::count
, но не могу заставить это работать.
Это то, что у меня есть на данный момент:
std::string setting;
std::string extension;
const auto count = std::range::count(setting | std::views::split(' '), extension);
И, к сожалению, ошибка MSVC не очень полезна:
ошибка C3889: вызов объекта типа класса 'std::ranges::_Count_fn': соответствующий оператор вызова не найден
Как я могу подсчитать элементы, соответствующие extension
, после разделения (без необходимости хранить части в контейнере)?
Это обходной путь, но я думал, что будет более короткое решение с представлениями и диапазонами.
@NathanOliver На самом деле, мне было бы интересно узнать, почему это не работает - какие требования отсутствуют в разделенном представлении, чтобы его можно было использовать в count
?
Я считаю, что проблема в том, что разделенное представление по сути является 2D-контейнером, поэтому, когда count
получает начальный итератор, этот итератор просто указывает на другой диапазон, и счетчик не может с этим справиться, поскольку ожидает, что объект будет соответствовать extension
.
subrange
после разделения нельзя сравнивать с string
, поэтому ограничение не выполняется.
Вы можете использовать проекцию, чтобы спроецировать их в string_view
, что делает их сравнимыми с string
:
std::string setting;
std::string extension;
const auto count = std::ranges::count(
setting | std::views::split(' '),
extension,
[](auto r) { return std::string_view(r.data(), r.size()); }
);
Или с помощью views::transform
:
const auto count = std::ranges::count(
setting | std::views::split(' ')
| std::views::transform(
[](auto r) { return std::string_view(r.data(), r.size()); }),
extension
);
Кажется, это не компилируется ни с MSVC, ни с clang, поскольку std::string_view(r)
недействительно (я использую C++20).
Хорошо, только что протестировал с clang, к сожалению, для конструктора std::string_view
требуется C++23.
@Holt Да, я обновил ответ для C++20.
Спасибо, я сделал то же самое, посмотрев en.cppreference.com/w/cpp/string/basic_string_view/… (я использовал .data()
вместо .begin()
).
@Холт Это моя опечатка.
Я всегда забываю о проекционной части диапазонов. Давайте сделаем так много изящных вещей.
std::string
и std::string_view
в настоящее время не являются равенством, сравнимым с элементами range::split_view
или ragne::lazy_split_view
. Я бы выбрал count_if
с equal
пердикатом:
const auto count = std::range::count_if
( setting
| std::views::split(' ')
, std::bind_front( std::ranges::equal
, std::cref(extension) )
);
Полностью C++20, никаких итераторов и явных циклов.
Более строгий подход будет использовать std::string::compare
в качестве пердиката:
const auto count = std::range::count_if
( setting
| std::views::split(' ')
, [&extension](auto const& r)
{ return not extension.compare(r); }
);
Используйте что-то вроде
for (auto&& word : setting | std::views::split(' '))
, чтобы перебрать разделения и подсчитать, совпадают ли ониextension
?