Boost logo

Boost :

Subject: Re: [boost] [type_traits] adding is_less_comparable<T>, etc.
From: Frédéric Bron (frederic.bron_at_[hidden])
Date: 2009-09-01 15:38:32


>> Once you know that operator< exists and returns non-void, you can
>> use simple overload resolution.
>>
>> typedef char no;
>> struct yes { no dummy[2]; };
>>
>> yes is_bool(bool);
>> no is_bool(...);
>>
>> sizeof(is_bool(T() < U())) == sizeof(yes);
>
> That assumes T and U have a default constructor.  Use a factory function to create T's and U's instead.

Very nice but I still cannot handle "convertible to bool". I have
tried to use boost::is_convertible but could not.
Here is my code and you can see that StrangeComparable objects give
the bad result.
Also I have manually entered all built-in types convertible to bool so
that they are handled properly but new types convertible to bool are
not handled.

Frédéric

#include <iostream>
#include <boost/type_traits/remove_cv.hpp>
#include <boost/type_traits/integral_constant.hpp>

namespace boost {
namespace detail {

// This namespace ensures that ADL doesn't mess things up.
namespace is_less_comparable_impl {

// a type returned from comparison operator when no such operator is
found in the
// type's own namespace
struct tag { } ;

// any soaks up implicit conversions and makes the following
// comparison operators less-preferred than any other such operators that
// might be found via ADL.
struct any { template <class T> any(T const&) ; } ;

tag operator<(const any&, const any&) ;

// two check overloads help us identify which comparison operator was picked

// check(not convertible to bool) returns a reference to char[2] (sizeof>1)
template <typename T> char (& check(T))[2] ;

// check(convertible to bool) returns char (sizeof==1)
template <typename T> char check(T*) ;
char check(bool) ;
char check(char) ;
char check(signed char) ;
char check(unsigned char) ;
char check(short) ;
char check(unsigned short) ;
char check(int) ;
char check(unsigned int) ;
char check(long) ;
char check(unsigned long) ;

template < typename T, typename U >
struct is_less_comparable_impl {
        static typename boost::remove_cv<T>::type &t ;
        static typename boost::remove_cv<U>::type &u ;
        static const bool value = sizeof(check(t<u))==1 ;
} ;

} // namespace impl
} // namespace detail

template< typename T, typename U=T >
struct is_less_comparable :
boost::integral_constant<bool,(::boost::detail::is_less_comparable_impl::is_less_comparable_impl<T,U>::value)>
{
} ;

} // namespace boost

// for testing
struct NotComparable { } ;
struct Comparable { bool operator<(const Comparable&) const ; } ;
struct IntComparable { int operator<(const IntComparable&) ; } ;
struct PtrComparable { void *operator<(const PtrComparable&) ; } ;
// this one has a strange operator<: it returns a non standard type
convertible to bool
struct Convertible { operator bool () const ; } ;
struct StrangeComparable { Convertible operator<(const StrangeComparable&) ; } ;

#define TEST1(T)\
        std::cout << boost::is_less_comparable<T, T>::value << "\t(" << #T <<
'<' << #T << ")\n"

#define TEST2(T1,T2)\
        std::cout << boost::is_less_comparable<T1, T2>::value << "\t(" << #T1
<< '<' << #T2 << ")\n" ;\
        std::cout << boost::is_less_comparable<T2, T1>::value << "\t(" << #T2
<< '<' << #T1 << ")\n"

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

        TEST1(NotComparable) ;
        TEST1(Comparable) ;
        TEST1(IntComparable) ;
        TEST1(PtrComparable) ;
        TEST1(StrangeComparable) ;

        TEST2(double, NotComparable) ;
        TEST2(int, NotComparable) ;
        TEST2(double, IntComparable) ;
        TEST2(int, IntComparable) ;
        TEST2(double, Comparable) ;
        TEST2(int, Comparable) ;

        TEST2(int, char) ;
        TEST2(int, short) ;
        TEST2(int, long) ;
        TEST2(int, float) ;
        TEST2(int, double) ;
        return 0 ;
}


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk