Transparent comparator code minimization

You may do as following:

struct Foo {
    std::string id;
};

struct FooComp {
    using is_transparent = std::true_type;

    template <typename LHS, typename RHS>
    bool operator()(const LHS& lhs, const RHS& rhs) const
    {
        return ProjectAsId(lhs) < ProjectAsId(rhs);
    }

private:
    const std::string& ProjectAsId(const std::string& s) const { return s; }
    const std::string& ProjectAsId(const Foo& foo) const { return foo.id; }
};

You write comparison once, but you have to write the projection for each type.

In C++17, it can even be

template <auto f> struct ProjLess
{
    using is_transparent = std::true_type;

    template <typename LHS, typename RHS>
    bool operator()(const LHS& lhs, const RHS& rhs) const
    {
        return project(lhs) < project(rhs);
    }

private:
    template <typename T>
    using f_t = decltype(std::invoke(f, std::declval<const T&>()));

    template <typename T>
    using is_f_callable = is_detected<f_t, T>;

    template <typename T, std::enable_if_t<is_f_callable<T>::value>* = nullptr>
    decltype(auto) project(const T& t) const { return std::invoke(f, t); }

    template <typename T, std::enable_if_t<!is_f_callable<T>::value>* = nullptr>
    const T& project(const T& t) const { return t; }
};

And usage:

std::set<Foo, ProjLess<&Foo::id>> s;

Demo with C++17

Tags:

C++

C++14