Is it legal for a standard comparison algorithm to accept objects of different types?

A response recently posted in the Stack Overflow section showed code that provides standard comparator algorithms that accept various types of operands:

2. Use a comparator with the operator() pattern.

Instead of using lambda, define a functor with the operator() pattern.

 struct comparator { template<typename T, typename U> bool operator()(T const& lhs, U const& rhs) const { return lhs.mCommonField < rhs.mCommonField; } }; 

Then it is as simple as:

 std::sort(aStructs.begin(), aStructs.end(), comparator{}); std::sort(bStructs.begin(), bStructs.end(), comparator{}); // ... std::set_intersection(aStructs.begin(), aStructs.end(), bStructs.begin(), bStructs.end(), std::back_inserter(intersection), comparator{} ); 

Note that since there is a template in the comparator, it must be declared outside the scope. Example in Coliru Viewer mode.

Apparently, this at least works in practice, as evidenced by the working demonstration.

But is it strictly permitted by the standard?

+7
c ++ c ++ 11
source share
1 answer

The relevant section in the standard is Β§25.4. The only requirements for the type of the Compare parameter are given in Β§25.4 / 2:

Compare is a type of function object. The return value of a function call operation applied to an object of type Compare , when contextually converted to bool , gives true if the first argument to the call is less than the second, and false otherwise. Compare comp used for algorithms involving an ordering relationship. It is assumed that comp will not apply any mutable function through a dereferenced iterator.

In other words, when called, it cannot change the values ​​indicated by iterators, and must give a strict weak order of values. Since this comparator satisfies both of these requirements, yes, it is legal!

In fact, this kind of comparison functor is exactly what N3421 offers - Creating operator functors greater<> , now part of the C ++ 14 standard. It provides void specializations for standard library functors that improve direct comparisons with the corresponding operator, if any. For example (taken from the application document):

 namespace std { template <> struct greater<void> { template <class T, class U> auto operator()(T&& t, U&& u) const -> decltype(std::forward<T>(t) > std::forward<U>(u)) { return std::forward<T>(t) > std::forward<U>(u); } }; } 
+11
source share

All Articles