
Thanks for all contributions. It works very fine now. 1. the key is the use of the ... argument instead of a template parameter 2. there is no difference between using a factory function and using a static reference to a value of the type -> I prefer the static reference 3. there is no difference between using pass/fail and return char or char[2] but pass/fail is easier to read -> I keep it
So the following code has the following properties: * returns true if t<u is meaningful and returns a value convertible to bool * returns false if t<u is meaningless. * fails with compile time error if t<u is meaningful and returns void
If you agree with the implementation, I will modify the sandbox accordingly and propose a new submission. Can I add your names in the copyright notice ? (Robert Stewart, Steven Watanabe, Roman Perepelitsa).
Please, are you happy with that? I would be very happy if included in the next version and deadline is 13th of Septembre. Thanks in advance, 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 does not 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&) ; } ;
// when operator< is not available, this one is used tag operator<(const any&, const any&) ;
typedef char pass ; struct fail { char dummy[2] ; } ;
pass is_bool(bool) ; // this version is preferred for types convertible to bool fail is_bool(...) ; // this version is used otherwise
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(is_bool(t<u)) == sizeof(pass) ; } ;
} // 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&) ; } ; struct VoidComparable { void operator<(const VoidComparable&) ; } ;
#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) ; // the following line triggers a compile time error //TEST1(VoidComparable) ;
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 ; }