0

I'd like to extract the differences between two sets. This question provides an adequate answer when I need the result in another container as well.

The following code demonstrates what I'd like to do:

std::set<std::string> s1, s2, difference;
std::string difference_string = "";
std::set_difference(
  s1.begin(), s1.end(), s2.begin(), s2.end(),
  std::inserter(difference, difference.end()));

for (const std::string& s: difference) {
  difference_string += s + ",";
}
if (0 < duplicateInPorts.size()) {
  difference_string.pop_back(); //remove last comma
}

except I find it inconvenient to create a local variable, when in essence I'd like to have a string only about the contents; Which I could easily compile with a lambda.

Is there a convenience function in std which would enable me to do that? What I had in mind has similar syntay as std::transform.

Dávid Tóth
  • 2,788
  • 1
  • 21
  • 46

1 Answers1

1

There isn't a convinience function in std, but there is one in boost.

The example for boost::function_output_iterator is almost exactly what you want. Slightly adapted:

struct string_joiner
{
    string_joiner(std::string& s)
        : m_str(s)
    {}

    void operator()(const std::string& x) const
    {
        m_str += m_sep;
        m_str += x;
        m_sep = ",";
    }

    std::string& m_str;
    std::string mutable m_sep;
};

int main(int, char*[])
{
  std::set<std::string> s1, s2;
  std::string difference = "";

  std::set_difference(
    s1.begin(), s1.end(),
    s2.begin(), s2.end(),
    boost::make_function_output_iterator(string_joiner(difference)));

  std::cout << difference << std::endl;

  return 0;
}

And function_output_iterator is just a wrapper around a callable that gives it the interface of an iterator. operator* returns a proxy who's operator= calls the function.

Caleth
  • 52,200
  • 2
  • 44
  • 75
  • shouldn't `std::inserter` work with a string by the way? – Dávid Tóth Apr 12 '22 at 10:32
  • 1
    @DávidTóth no, that can only insert individual `char`s or `std::initializer_list`. It will call [`std::string::insert`](https://en.cppreference.com/w/cpp/string/basic_string/insert) with an iterator and a value. – Caleth Apr 12 '22 at 10:39
  • actually not even initializer_list, `std::insert_iterator` only operates on references to the [container's `value_type`](https://en.cppreference.com/w/cpp/iterator/insert_iterator/operator%3D) – Caleth Apr 12 '22 at 10:56