0

I would like to use set_union() and just scan the output without having to store it.

Something like this (it doesn't compile using g++12.1.0):

#include <vector>
#include <algorithm>
#include <stdio.h>
using namespace std;

int main()
{
    vector<int> a = {1,2,3}, b={4,5,6};
    ranges::set_union(a, b, [](int i){printf("%d,",i);});
}
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
Ludovic Aubert
  • 9,534
  • 4
  • 16
  • 28
  • 1
    You need to provide an "output iterator" as he third parameter. You need to make that type act like an iterator but not actually do anything except output when a value is assigned through it. – NathanOliver Jul 25 '22 at 21:43
  • Wouldn't `#include ` be a good idea to start out with? Sidenote: ``? Really? – Ted Lyngmo Jul 25 '22 at 21:44
  • 2
    @TedLyngmo `ranges::set_union` lives in ``: https://en.cppreference.com/w/cpp/algorithm/ranges/set_union – NathanOliver Jul 25 '22 at 21:45
  • 1
    @NathanOliver Ah... utter confusion on my part – Ted Lyngmo Jul 25 '22 at 21:46
  • Looks like `boost::function_output_iterator` could be one way to solve this. [Documentation here.](https://www.boost.org/doc/libs/1_79_0/libs/iterator/doc/function_output_iterator.html) – aschepler Jul 25 '22 at 22:12

2 Answers2

3

You need to supply an "output iterator" for set_union() to pass elements to. It does not accept a lambda (or other callable type). You can use std::ostream_iterator for this, eg:

#include <vector>
#include <algorithm>
#include <iterator>
#include <iostream>
// ...
vector<int> a = {1,2,3}, b={4,5,6};
ranges::set_union(a, b, std::ostream_iterator<int>(std::cout, ","));
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
Unmitigated
  • 76,500
  • 11
  • 62
  • 80
0

You can write your own set_union() function to call a Lambda, if the one provided in the stl is not (yet?) capable. It (avoiding having to store the output) will be very well adressed by views::set_union() possibly C++23 but I am not sure if it really is in store.

#include <vector>
#include <stdio.h>
using namespace std;


template <typename Range, typename F>
void set_union(const Range& a, const Range& b, F&& f)
{
    for (int i=0, j=0; i<a.size() || j<b.size();)
    {
        if (i < a.size() && j<b.size())
        {
            if (a[i] < b[j])
            {
                f(a[i++]);
            }
            else if (a[i] > b[j])
            {
                f(b[j++]);
            }
        }
        else if (i < a.size())
        {
            f(a[i++]);
        }
        else if (j < b.size())
        {
            f(b[j++]);
        }
    }    
}

int main(int argc, char* argv[])
{
    vector<int> a = {1, 2, 6}, b = {3, 4, 5, 7};
    
    set_union(a, b, [](const int& i){printf("%d,", i);});

    return 0;
}

enter image description here

Ludovic Aubert
  • 9,534
  • 4
  • 16
  • 28