Есть ли способ суммировать диапазон С++ 20, кроме итерации по нему?
Я решаю задачи из Project Euler, чтобы улучшить свои навыки C++, и хотел решить задачу 37 с помощью библиотеки std::ranges.
Мой код выглядит примерно так:
#include <iostream>
#include <ranges>
#include <numeric>
using namespace std;
bool is_truncatable(const int n)
{
// Blah blah...
}
int truncatable_primes()
{
const auto range = views::iota(10); // Goes on to infinity.
const int total_num_of_truncatable_primes = 11; // Given.
auto all_truncatable_primes = range | views::filter([] (int n) { return is_truncatable(n); })
| views::take(total_num_of_truncatable_primes);
const int sum = accumulate(all_truncatable_primes.begin(), all_truncatable_primes.end(), 0); // Does not compile.
return sum;
}
int main()
{
const auto answer = truncatable_primes();
cout << answer << endl;
return EXIT_SUCCESS;
}
Поскольку диапазона ranges::accumulate пока нет, существует ли идиоматический способ суммировать диапазон all_truncatable_primes
, или я вынужден использовать цикл for?
Вы можете добавить | views::common
, чтобы его можно было использовать со стандартным алгоритмом:
auto all_truncatable_primes = range | views::filter([] (int n) { return is_truncatable(n); })
| views::take(total_num_of_truncatable_primes)
| views::common;
const int sum = accumulate(all_truncatable_primes.begin(), all_truncatable_primes.end(), 0);
all_truncatable_primes
не является common_range
, а это означает, что его begin()
и end()
имеют разные типы.
Это несовместимо с алгоритмами C++98, которые требуют, чтобы оба были одного типа (например, std::accumulate
). Один из вариантов — применить views::common
, чтобы сделать common_range
:
auto all_truncatable_primes = range | views::filter([] (int n) { return is_truncatable(n); })
| views::take(total_num_of_truncatable_primes)
| views::common;
const int sum = accumulate(all_truncatable_primes.begin(), all_truncatable_primes.end(), 0);
Более подходящий способ — использовать C++23 ranges::fold_left, который можно рассматривать как версию диапазона std::accumulate
:
auto all_truncatable_primes = range | views::filter([] (int n) { return is_truncatable(n); })
| views::take(total_num_of_truncatable_primes);
const int sum = ranges::fold_left(all_truncatable_primes, 0, std::plus{});
std::ranges::fold_left(rng, 0, std::plus<>{});
. Для непустых диапазонов естьfold_right
иfold_left_first
. Но это C++23.