patentfox
patentfox

Reputation: 1464

Why does comparison function type need to specified as template parameter?

For associative containers in C++, like set, map etc, we need to provide the custom key comparator type as a template parameter as follows.

bool compareMyType(const MyType& a, const MyType& b);

set<MyType, decltype(compareMyType)*> my_set(compareMyType); // OK
set<MyType> my_set(compareMyType); // ERROR

Why is this required? Why can't the type of comparator function be deduced by the type of key?

Upvotes: 0

Views: 185

Answers (3)

Ted Lyngmo
Ted Lyngmo

Reputation: 117298

Your question has been answered so this is just input to how you could work around the problem:

You could supply operator< for your type to avoid having to supply a less functor for it every time you use it in a set.

#include <iostream>
#include <set>

struct MyType {
    int value;
};

// added operator<
bool operator<(const MyType& l, const MyType& r) {
    return l.value < r.value;
}

int main() {
    std::set<MyType> my_set = {{3}, {2}, {1}};
    for(const MyType& m : my_set) 
        std::cout << ' ' << m.value;
    std::cout << "\n";
}

Output:

 1 2 3

If you want to use it with hash based containers (like unordered_set), you can similarly add a std::hash<MyType> class that will be used per default for your type.

Upvotes: 2

NathanOliver
NathanOliver

Reputation: 180585

Unlike functions, there is no partial deduction for class templates. If you provide template parameters to a class template then you need to provide all non defaulted parameters, and in set's case you need to provide the comparison type since it defaults to std::less<T>, which your function pointer is not convertible to.

There was a proposal to get partial deduction, but it was rejected and the only current thing being added to CTAD is that it will work through an alias.

Upvotes: 4

Quentin
Quentin

Reputation: 63124

Because the comparator is not necessarily a function (function pointer, even). In fact, the default value for that parameter is std::less<Key>, which is a class template with an operator(). But you could pass the type of anything that can be called with two MyType const& and return a bool, hence the need to specify what that thing actually is.

Upvotes: 1

Related Questions