0

I have a function that operates on standard iterators of a common type:

template <typename I>
bool next_combination(const I first, I k, const I last)

I'm trying to use it with std::ranges::views, but I'm not able to pass its iterators as input arguments to the function:

auto view = std::ranges::views::split(';') |
        std::ranges::views::transform(
            [](auto &&rng)
            {
            bool ok = next_combination(rng.begin(),rng.begin() + 2, rng.end());
            // ...
            }

The view-iterators does not support operator+ for the second input argument of next_combination, and the begin and end iterator types are different.

How do I adapt function next_combination to handle ranges/views, or (alternatively) adapt the input arguments in order to make this compile?

Edit: Full example:

#include <string>
#include <ranges>
#include <span>
#include <vector>
#include <algorithm>

template <typename I>
bool next_combination(const I first, I k, const I last)
{
    /* Credits: Mark Nelson http://marknelson.us */
    if ((first == last) || (first == k) || (last == k))
        return false;
    I i1 = first;
    I i2 = last;
    ++i1;
    if (last == i1)
        return false;
    i1 = last;
    --i1;
    i1 = k;
    --i2;
    while (first != i1)
    {
        if (*--i1 < *i2)
        {
            I j = k;
            while (!(*i1 < *j))
                ++j;
            std::iter_swap(i1, j);
            ++i1;
            ++j;
            i2 = k;
            std::rotate(i1, j, last);
            while (last != j)
            {
                ++j;
                ++i2;
            }
            std::rotate(k, i2, last);
            return true;
        }
    }
    std::rotate(first, k, last);
    return false;
}

int main()
{
    std::string line;
    std::vector<std::string> lines{"bcd;zac", "cad;c"};

    auto strsplit_view =
        std::ranges::views::split(';') | std::ranges::views::drop(1) |
        std::ranges::views::transform(
            [](auto &&rng)
            {
            bool ok = next_combination(rng.begin(),rng.begin() + 2, rng.end());
            return std::span(&*rng.begin(), std::ranges::distance(rng)); });

    auto filesplit_view = lines | std::ranges::views::transform(
                                      [&](auto &&line)
                                      { return line | strsplit_view; });

}
康桓瑋
  • 33,481
  • 5
  • 40
  • 90
Jonas Hjulstad
  • 395
  • 1
  • 8
  • My code does not compile – Jonas Hjulstad Feb 01 '22 at 15:05
  • 1
    What compiler+version are you using and what exactly is the error message? Your compiler is probably not implementing P2210R2 yet, see https://en.cppreference.com/w/cpp/compiler_support. – user17732522 Feb 01 '22 at 15:28
  • g++ 12.0.1 is able to handle this code correctly, but my current g++ 11.0.1 configuration does not. I'm not able to find a git release for 12.0.1 on GNU's pages, so it would be nice with a 11.0.1 solution – Jonas Hjulstad Feb 01 '22 at 15:29

1 Answers1

2

You are using a version of gcc that has not yet implemented the P2210, that is, the split subranges obtained by views::split (renamed views::lazy_split in the latest standard) can only be a forward_range.

Since next_combination requires bidirectional_iterators (which support operator--), you cannot pass an iterator of forward_range to it.

There is no simple solution until using a compiler that implements P2210.

康桓瑋
  • 33,481
  • 5
  • 40
  • 90