简体   繁体   中英

C++ class template specialization for functors

The std::set has the below template parameters:

template<typename _Key, typename _Compare = std::less<_Key>,
         typename _Alloc = std::allocator<_Key> >
class set

And std::greater has the below template parameter:

template<typename _Tp>
struct greater : public binary_function<_Tp, _Tp, bool>

The below declarations can both be compiled on gcc 7.1. I don't understand why the second declaration is valid. Is it a C++14 feature? Is the rule defined somewhere in the standard?

std::set<int, std::greater<int>> s1;
std::set<int, std::greater<>> s2;

Is it a C++14 feature?

Yes, it is :

template< class T >
struct greater; // Until C++14

template< class T = void >
struct greater; // Since C++14

Without type T specified, it gets the default one, void .

It is a C++14 standard library feature called transparent comparators .

The below declarations can both be compiled

 std::set<int, std::greater<int>> s1; std::set<int, std::greater<>> s2; 

The second variant allows for a heterogeneous comparison . Not a big deal in the case of int but consider the example from N3657:

std::set<std::string> s = /* ... */;
s.find("key");

In old C++11 this will construct a string temporary in order to invoke less(string, string) .

With a transparent comparator in C++14, less::operator() (const string&, const char*) 1 will be generated automatically which will invoke bool operator< (const string&, const char*) , thus avoiding the temporary.

The way it's implemented is:

template< class T = void >
struct greater;

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));
};

That is, when no T is specified, it defaults to void , which in C++14 has a specialization that accepts heterogeneous parameters. The assumption here is that no-one would use std::greater<void> in older code, so the risk of existing code breaking is small.

For more details see the proposals N3421 , which introduces the "diamond operators", and N3657 , which introduces std::is_transparent .


1 Disclaimer: the exact deduced types may be different, this is just to illustrate the core concept without getting into too much detail.

Is the rule defined somewhere in the standard?

From comparisons.greater :

template<class T = void> struct greater {
  constexpr bool operator()(const T& x, const T& y) const;
};

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