简体   繁体   中英

implement my own myless

I am trying to understad how std::less is implemented so I can say

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

template <typename A, typename B, typename U = myless> // std::less works
bool f(A a, B b, U u = U())
{
    return u(a, b);
}

int main() 
{
    std::cout << std::boolalpha;

    std::cout << f("AB/CD", "CD/AB") << '\n';
    std::cout << f(100, 10) << '\n';
}

This doesn't work. Any suggestions?

There is a typo in f("AB/CD", "CD/AB",) (comma). It should be typename U = myless<A> because myless is not in the std namespace. Also the parameters should probably be passed by reference: bool f(const A& a, const B& b, const U& u = U()) .

std::less needs both operands to be of the same type (logically), and myless is also defined like that. So using myless<A> for U would make it convert the B object to A for the comparing (by creating a temporary using its copy-constructor).

Since C++14, there is also the specialization std::less<void> where the operand can have different types, and a return type that is not bool. It maps one-to-one to what the operator< does. See http://en.cppreference.com/w/cpp/utility/functional/less_void .

Corrected version of the code:

#include <iostream>

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

template <typename A, typename B, typename U = myless<A>>
bool f(const A& a, const B& b, const U& u = U())
{
    return u(a, b);
}

int main() 
{
    std::cout << std::boolalpha;

    std::cout << f("AB/CD", "CD/AB") << '\n';
    std::cout << f(100, 10) << '\n';
}

For a version that can have different types, and non-bool return type:

struct myless2 {
    template<class T, class U>
    constexpr auto operator()(const T& t, const U& u) const -> decltype(t < u) {
        return t < u;
    }
};

std::less<void> seems to also support r-value references, for when the operator< is defined like that (probably doing something else than comparation then.)

Your myless template takes a single type but your f function takes two types (ie, they might be different types). It's possible to support this but it's more involved. Did you intend to do the following instead?

template<typename T, typename U = myless<T>>
bool f(T a, T b, U u = U())
{
    return u(a, b);
}

Edit

As @vscoftco pointed out supporting different types may have been an intended use case. If different types were to be explicitly supported then I would have implemented it like this.

template<typename A, typename B, typename U = myless<typename std::common_type<A, B>::type>>
bool f(A a, B b, U u = U())
{
    return u(a, b);
}

It also appears this solution is SFINAE compatible (C++17), http://en.cppreference.com/w/cpp/types/common_type .

If sizeof...(T) is zero or if there is no common type, the member type is not defined (std::common_type is SFINAE-friendly)

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