简体   繁体   中英

C++ custom Compare types used in STL (function predicate vs. less struct)

I've check the prototype of std::sort and std::priority_queue, the custom Compare type defined in the template looks quite the same.

template< class RandomIt, class Compare >
void sort( RandomIt first, RandomIt last, Compare comp );

template <class T, class Container = vector<T>,
  class Compare = less<typename Container::value_type> > class priority_queue;

But actually they differ, std::sort accepts a function predicate, while std::priority_queue accepts a struct(a type). Why? Thanks in advance!.

struct cmp {
    bool operator() (const int &a, const int &b) {
        return a < b;
    }
};

vector<int> v;
v.push_back(2);
v.push_back(3);
v.push_back(1);
// this works
sort(v.begin(), v.end(), [](const int &a, const int &b) -> bool {
    return a < b;
});
// this not works
// sort(v.begin(), v.end(), cmp);
cout << v[0] << endl;

// this works
priority_queue<int, cmp> q;
// this not works
// priority_queue<int, [](const int &a, const int &b) -> bool {
//     return a < b;
// }> q;
q.push(2);
q.push(3);
q.push(1);
cout << q.top() << endl;

The difference is that sort is a function template and thus the template argument for Comparator can be deduced from the type of the function argument. When you call it like this:

sort(v.begin(), v.end(), [](const int &a, const int &b) -> bool {
    return a < b;
});

then the argument for Comparator is deduced to be the type of the lambda closure object.

priority_queue , on the other hand, is a class template. There's no type deduction. You specify the template argument for Compare in the type of q , and afterwards, you can only supply a function argument (to the constructor) of the appropriate type.

To use a lambda with a priority queue, you'd need to get hold of its type:

auto compare = [](const int &a, const int &b) -> bool {
  return a < b;
};

std::priority_queue<int, std::vector<int>, decltype(compare)> q(compare);

You were trying to pass a lambda expression as an argument to a template type parameter. This can't work. Doing the same with sort wouldn't work either:

sort<vector<int>::iterator, [](const int &a, const int &b) -> bool {
    return a < b;
}>(/*...*/);

They are actually the same, the difference is in that one is a class template and the other a function template.

Here's what you can do with the priority queue:

auto comp = [](const int& a, const int& b) { return a < b; };
priority_queue<int, std::vector<int>, decltype(comp)> q(comp);

The difference is that for function templates, the compiler will deduce template parameters from the function parameters supplied, while it won't do that for class templates. So you have to supply the type explicitly, and with a lambda (which has an anonymous type), this is annoying.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM