Itay Maman
Itay Maman

Reputation: 30723

C++/STL Default comparator

I ma writing a template function that takes a vector of elements and does a sequence of some operations on it. One of these operation is std::sort().

Naturally, client code needs to supply a comparator functor. I do not want the client code to specify a value for this parameter if it passes in a container of well-known types (ints, strings, etc.). How should I define the default value of my Comp template parameter?

template<typename Container, typename Comp=????>
void my_func(Container elements, Comp comp) {
  ...
  std::sort(elements.begin(), elements.end(), comp);
  ...
}

Upvotes: 1

Views: 1814

Answers (4)

Galimov Albert
Galimov Albert

Reputation: 7357

In your example there is 2 issues:

  1. to make default behavior you must suplly less<T> as a functor.

  2. Your function is taking a copy so, the copy will be sorted, unless you take a refence to Container instead.

Example how to make this:

#include <functional>
template<typename Container, typename Comp=std::less<typename Container::value_type> >
void my_func(Container &elements, Comp comp = Comp() )
{
  std::sort(elements.begin(), elements.end(), comp);
}
// A partial specialisation for std::list
#include <list>
template<typename ContainerValueType, typename Allocator, typename Comp=std::less<ContainerValueType> >
void my_func(std::list<ContainerValueType, Allocator> &elements, Comp comp = Comp() )
{
  elements.sort(comp);
}

Upvotes: 0

AngelCastillo
AngelCastillo

Reputation: 2435

std::sort uses "Less" as default comparator. So to keep it consistent:

template<typename Container, typename Comp = std::less<typename Container::value_type> >
void my_func(Container& elements, Comp comp = Comp())
{
  std::sort(elements.begin(), elements.end(), comp);
}

Upvotes: 2

Rapptz
Rapptz

Reputation: 21317

I wouldn't default the template itself but rather the parameter of the function into something akin to std::greater or std::less for > and < respectively. std::sort uses std::less by default.

If you want to get the template parameter for it then there is a proposal to make std::greater<> to work for generalised types called N3421 that was actually accepted for C++14.

However until then you can do std::greater<typename Container::value_type>. You can opt to remove the reference or cv qualifiers using type_traits if you wish.

<functional> has other default comparisons but those two are the most common.

So a "complete" solution would be something like this:

template<typename Container, typename Comp>
void my_func(Container& elements, Comp comp = std::less<typename Container::value_type>()) {
  std::sort(elements.begin(), elements.end(), comp);
}

Upvotes: 0

RiaD
RiaD

Reputation: 47619

#include <vector>
#include <algorithm>

template<typename Container, typename Comp=std::less<typename Container::value_type>>
void my_func(Container elements, Comp comp = Comp()) {
  //...
  std::sort(elements.begin(), elements.end(), comp);
  //...
}

int main() {
    std::vector<int> v;
    my_func(v);
}

Note also Comp comp = Comp()

Upvotes: 0

Related Questions