Search code examples
c++11type-traits

Looking for "is_comparable" typetrait


I'm looking for an "is_comparable<>" typetrait but can't find any.

It's very easy to build one that checks if an operator== for a class was implemented, but this excludes global defined operators.

Is it impossible to implement a generic is_comparable<> typetrait?


Solution

  • I take it you mean a trait that, for two types L and R and objects lhs and rhs of those types respectively, will yield true if the lhs == rhs will compile and false otherwise. You appreciate that in theory lhs == rhs might compile even though rhs == lhs, or lhs != rhs, does not.

    In that case you might implement the trait like:

    #include <type_traits>
    
    template<class ...> using void_t = void;
    
    template<typename L, typename R, class = void>
    struct is_comparable : std::false_type {};
    
    template<typename L, typename R>
    using comparability = decltype(std::declval<L>() == std::declval<R>());
    
    template<typename L, typename R>
    struct is_comparable<L,R,void_t<comparability<L,R>>> : std::true_type{};
    

    This applies a popular SFINAE pattern for defining traits that is explained in the answer to this question

    Some illustrations:

    struct noncomparable{};
    
    struct comparable_right
    {
        bool operator==(comparable_right const & other) const {
            return true;
        }
    };
    
    struct any_comparable_right
    {
        template<typename T>
        bool operator==(T && other) const {
            return false;
        }
    };
    
    bool operator==(noncomparable const & lhs, int i) {
        return true;
    }
    
    #include <string>
    
    static_assert(is_comparable<comparable_right,comparable_right>::value,"");
    static_assert(!is_comparable<noncomparable,noncomparable>::value,"");
    static_assert(!is_comparable<noncomparable,any_comparable_right>::value,"");
    static_assert(is_comparable<any_comparable_right,noncomparable>::value,"");
    static_assert(is_comparable<noncomparable,int>::value,"");
    static_assert(!is_comparable<int,noncomparable>::value,"");
    static_assert(is_comparable<char *,std::string>::value,"");
    static_assert(!is_comparable<char const *,char>::value,"");
    static_assert(is_comparable<double,char>::value,"");
    

    If you want the trait to require that equality is symmetric and that inequality also exists and is symmetric you can see how to elaborate it yourself.