Home > Back-end >  Why this template class works, despite using std::less oddly
Why this template class works, despite using std::less oddly

Time:12-02

This code works:

#include <iostream>

constexpr static auto less = std::less{};

#include <string>

std::string a = "1";
std::string b = "1";

int main(){
    std::cout << ( less( 6, 3 ) ? "Y" : "N" ) << '\n';
    std::cout << ( less( a, b ) ? "Y" : "N" ) << '\n';
}

According en.cppreference.com, std::less is implemented like this:

template<class T>
struct Less{
    constexpr bool operator()(const T &lhs, const T &rhs) const{
        return lhs < rhs;
    }   
};

but if this is true, how std::less{}; works? It will require to pass the type - std::less<int>{};

Alternatively, if implementation is like this:

struct Less{
    template<class T>
    constexpr bool operator()(const T &lhs, const T &rhs) const{
        return lhs < rhs;
    }   
};

everything will works.

But if this is like it is, why use class and not lambda?

Strangely enough, but this code also works:

#include <iostream>

constexpr static auto less = std::less<int>{};

#include <string>

std::string a = "1";
std::string b = "1";

int main(){
//  obviously for strings it no longer works.
//  std::cout << ( less( 6, 3 ) ? "Y" : "N" ) << '\n';
    std::cout << ( less( a, b ) ? "Y" : "N" ) << '\n';
}

So what is really going on here?

CodePudding user response:

Since C 14 std::less is declared as

template< class T = void >
struct less;

and it has a specialization for void that has an operator() with the form of

template< class T, class U>
constexpr auto operator()( T&& lhs, U&& rhs ) const
  -> decltype(std::forward<T>(lhs) < std::forward<U>(rhs));

This operator() deduces the types of the parameters for you and returns lhs < rhs. This is what allows your first code block to compile.

In your second example you switch less to be

constexpr static auto less = std::less<int>{};

and this forces you to have comparator that only works for ints.

CodePudding user response:

Code for illustrating my comment to NathanOliver:

template<class T = void>
struct Less{
    constexpr bool operator()(const T &lhs, const T &rhs) const{
        return lhs < rhs;
    }   
};

template<>
struct Less<void>{
    template<class A, class B>
    constexpr bool operator()(const A &lhs, const B &rhs) const{
        return lhs < rhs;
    }   
};
  • Related