5

When using the functions in <algorithm>, there is usually one extra argument to customize the comparison. But I am not quite understand about the description about the argument (Documentation of set_intersection).

Binary function that accepts two arguments of the types pointed by the input iterators, and returns a value convertible to bool. The value returned indicates whether the first argument is considered to go before the second in the specific strict weak ordering it defines. The function shall not modify any of its arguments. This can either be a function pointer or a function object.

It describes that the function should return the order of two arguments. But what about in the matching function, For example:

#include <algorithm>
#include <iostream>

using namespace std;

void print (const char* name, int* start, int* end) {
    cout << name << ": ";
    while (start < end) 
        cout << *start++ << ", ";
    cout << endl;
}

bool func1 (int a, int b) { return a==b; }
bool func2 (int a, int b) { return a+b == 8; }

int main() {
  int set1[6] = {0, 1, 2, 4, 2, 4};
  int set2[6] = {1, 2, 3, 4, 5, 6};

  int set_without_comp[6];
  int* end_wo = set_intersection(set1, set1+6, set2, set2+6, set_without_comp);
  print ("set_without_comp", set_without_comp, end_wo);

  int set_with_comp1[6];
  int *end_w1 = set_intersection(set1, set1+6, set2, set2+6, set_with_comp1, func1);
  print ("set_with_comp1", set_with_comp1, end_w1);

  int set_with_comp2[6];
  int *end_w2 = set_intersection(set1, set1+6, set2, set2+6, set_with_comp2, func2);
  print ("set_with_comp2", set_with_comp2, end_w2);
}

We get outputs:

set_without_comp: 1, 2, 4, 
set_with_comp1: 0, 1, 2, 2, 4, // Expect 1, 2, 4, 
set_with_comp2: 0, 1, 2, 2, 4, // Expect 2, 4, (maybe 6)

How to interpret the results, and what is the right way to write a comparison function in using of <algorithm> functions, and how to write one that can give me the expected results?

Panwen Wang
  • 3,573
  • 1
  • 18
  • 39
  • It accepts an argument like `std::less` — basically, an `operator<`, as do all other algorithms that operate on an ordering. – Konrad Rudolph Jul 24 '15 at 08:12
  • @Konrad Rudolph But sometimes I don't need the order, I just need to match the elements, just like what I wrote in the post, the `set_intersection` supposed to find the matched elements in both sets, instead of orders. – Panwen Wang Jul 24 '15 at 08:14
  • In the C++ standard algorithm, all this is expressed via an ordering (because that helps implement set operations efficiently). Two elements are equal if neither of them is larger than the other. – Konrad Rudolph Jul 24 '15 at 08:15
  • Not sure, but I think you are supposed to provide a total-order function. – Paolo M Jul 24 '15 at 08:17
  • Please, select an answer as a solution if you think your question has been cleared. – ChronoTrigger Jul 24 '15 at 11:25

3 Answers3

3

std::set_intersection expects a function that relates two elements in the same way they are stored in the set. It's not a function to describe what elements are the same, because the function does that work internally.

So, in your example, set1 is not a proper set because it's not in order (ascending order, for example). If it was in order, you could use in std::set_intersection the same order function. For example:

int set1[6] = {0, 1, 2, 2, 2, 4}; // in order (<)

bool func1 (int a, int b) { return a < b; } // the only valid function

The ability to explicitly say what order function you want to use is useful when you deal with complex objects that don't have a implicit order. For example:

struct Person {
  std::string name;
  int age;
};

bool ascendingAge(const Person& guy1, const Person& guy2) {
  return guy1.age < guy2.age;
}

...

std::intersection(..., ..., ascendingAge);
ChronoTrigger
  • 8,459
  • 1
  • 36
  • 57
  • I changed set1 and set2 as follows: `int set1[6] = {0, 1, 2, 2, 4, 4}; int set2[6] = {1, 2, 3, 4, 5, 6};`, which are in a certain order, and the compare function as: `bool func1 (int a, int b) { return a>b; } bool func2 (int a, int b) { return a – Panwen Wang Jul 24 '15 at 08:26
  • So you mean that the function is just used to indicate the order the set holds, instead of to compare the elements in both sets. And the purpose for that is to reduce the complexity? – Panwen Wang Jul 24 '15 at 08:27
  • Yes, it's to indicate the order the set holds. The purpose of this is to increase the flexibility to manage non-trivial classes. – ChronoTrigger Jul 24 '15 at 08:38
  • But for some cases, for example, `std::search`, the function seems to compare two values. It is really confused that in `std::set_intersection` it not comparison but ordering. – Panwen Wang Jul 24 '15 at 08:43
  • 1
    @PanwenWang The reason is that the `std::search` algorithm works differently. Different algorithms come with different requirements. It just so happens that an efficient set intersection algorithm requires that elements are comparable by some ordering, and searching in an unordered list does not have such a requirement. That’s simply a fundamental truth about algorithms. – Konrad Rudolph Jul 24 '15 at 08:45
1

Neither bool func1 (int a, int b) { return a==b; }, nor bool func2 (int a, int b) { return a+b == 8; } answer whether a must go before b. The results you get after passing such functions as comparators cannot be "interpreted": they are implementation-dependent nonsense because STL is used wrongfully - it expects a function that says whether a must go before b, but gets a function that does something else. Some examples of valid comparators are:

bool func1 (int a, int b) { return a<b; }
bool func2 (int a, int b) { return a>b; }
Serge Rogatch
  • 13,865
  • 7
  • 86
  • 158
1

The comparison function provides a sorting order. The default is std::less and here is how to write such functions. If you want to keep the ascending sort order for the integers, just keep the default and don't specify any comparison function.

Community
  • 1
  • 1
V-R
  • 1,309
  • 16
  • 32