ryanhaining / cppitertools

Implementation of python itertools and builtin iteration functions for C++17
https://twitter.com/cppitertools
BSD 2-Clause "Simplified" License
1.37k stars 115 forks source link

Nesting with Combinations Compilation Issue in MSVC #96

Closed ryandougherty closed 1 year ago

ryandougherty commented 1 year ago

Hi, I have the following code snippet that does not compile in MSVC (if it helps, I'm using Visual Studio 2022):

auto cols = combinations(range(k), t);
auto d_sets = combinations(cols, d);
for (const auto& d_set : d_sets) { ... }

Attached is a screenshot of MSVC's output. All variables k, t, d are unsigned integers. It appears that the errors have nothing to do with this project's actual code (or mine), but within the xmemory and xutility headers. I have no idea why these are happening. I have an equivalent Python version which works.

image

The error goes away if I remove the for loop. The inside of the loop has nothing to do with the error; even with nothing in it I still get compilation errors.

ryanhaining commented 1 year ago

I'm afraid the answer here is going to be pretty unsatisfying, but you will need to throw in some extra steps to make this work.

Combinations is one of a few itertools that requires that the thing you pass to it have a ForwardIterator, but, combinations itself only provides an InputIterator.

The general advice if you need an itertool to behave like a forward iterable (or anything more functional than an input iterable) is to expand it into a vector or other container, the simplest (not pretty) way to do it here imo is:

auto cols_comb = iter::combinations(iter::range(3), 2);
auto m = iter::imap([] (auto&& c) {
      // expand the inner iterables as well.
      return std::vector<int>(c.begin(), c.end());
    }, cols_comb);
auto cols = std::vector<std::vector<int>>(m.begin(), m.end());

The rest of the code should work given that

#include "cppitertools/imap.hpp"
#include "cppitertools/combinations.hpp"
#include "cppitertools/range.hpp"

#include <iostream>
#include <vector>

int main() {
  auto cols_comb = iter::combinations(iter::range(3), 2);
  auto m = iter::imap([] (auto&& c) {
        return std::vector<int>(c.begin(), c.end());
      }, cols_comb);
  auto cols = std::vector<std::vector<int>>(m.begin(), m.end());

  auto d_sets = iter::combinations(cols, 2);

  for (const auto& d_set : d_sets) { 
    std::cout << "{ ";
    for (const auto& d : d_set) {
      std::cout << "{ ";
      for (const auto & i : d) {
        std::cout << i << " ";
      }
      std::cout << "} ";
    }
    std::cout << "}\n";
  }
}