// DR 339 // // Test of the use of various binary operators with SFINAE // Boilerplate helpers typedef char yes_type; struct no_type { char data[2]; }; template T create_a(); template struct type { }; template struct enable_if { typedef T type; }; template struct enable_if { }; #define JOIN( X, Y ) DO_JOIN( X, Y ) #define DO_JOIN( X, Y ) DO_JOIN2(X,Y) #define DO_JOIN2( X, Y ) X##Y #define DEFINE_INFIX_BINARY_TRAIT(Name,Op) \ template \ typename enable_if<(sizeof(create_a() Op create_a(), 1) > 0), \ yes_type>::type \ JOIN(check_,Name)(type, type); \ \ no_type JOIN(check_,Name)(...); \ \ template \ struct Name \ { \ static const bool value = \ (sizeof(JOIN(check_,Name)(type(), type())) == sizeof(yes_type)); \ } template typename enable_if<(sizeof(create_a()[create_a()], 1) > 0), yes_type>::type check_subscript(int); template no_type check_subscript(...); template struct can_subscript { static const bool value = (sizeof(check_subscript(0)) == sizeof(yes_type)); }; #ifdef __GXX_EXPERIMENTAL_CXX0X__ # define STATIC_ASSERT(Expr) static_assert(Expr, #Expr) #else # define STATIC_ASSERT(Expr) int JOIN(a,__LINE__)[Expr? 1 : -1] #endif struct X { }; struct Y { int operator[](X); }; // is_addable DEFINE_INFIX_BINARY_TRAIT(is_addable, +); X operator+(X, X); X operator+(X, Y); STATIC_ASSERT((is_addable::value)); STATIC_ASSERT((is_addable::value)); STATIC_ASSERT((is_addable::value)); STATIC_ASSERT((is_addable::value)); STATIC_ASSERT((!is_addable::value)); STATIC_ASSERT((is_addable::value)); STATIC_ASSERT((!is_addable::value)); // is_subtractable DEFINE_INFIX_BINARY_TRAIT(is_subtractable, -); X operator-(X, X); X operator-(X, Y); STATIC_ASSERT((is_subtractable::value)); STATIC_ASSERT((is_subtractable::value)); STATIC_ASSERT((is_subtractable::value)); STATIC_ASSERT((is_subtractable::value)); STATIC_ASSERT((is_subtractable::value)); STATIC_ASSERT((is_subtractable::value)); STATIC_ASSERT((!is_subtractable::value)); STATIC_ASSERT((!is_subtractable::value)); // is_multiplicable DEFINE_INFIX_BINARY_TRAIT(is_multiplicable, *); X operator*(X, X); X operator*(X, Y); STATIC_ASSERT((is_multiplicable::value)); STATIC_ASSERT((is_multiplicable::value)); STATIC_ASSERT((is_multiplicable::value)); STATIC_ASSERT((!is_multiplicable::value)); STATIC_ASSERT((!is_multiplicable::value)); STATIC_ASSERT((is_multiplicable::value)); STATIC_ASSERT((!is_multiplicable::value)); STATIC_ASSERT((!is_multiplicable::value)); // is_divisible DEFINE_INFIX_BINARY_TRAIT(is_divisible, /); X operator/(X, X); X operator/(X, Y); STATIC_ASSERT((is_divisible::value)); STATIC_ASSERT((is_divisible::value)); STATIC_ASSERT((is_divisible::value)); STATIC_ASSERT((!is_divisible::value)); STATIC_ASSERT((!is_divisible::value)); STATIC_ASSERT((is_divisible::value)); STATIC_ASSERT((!is_divisible::value)); STATIC_ASSERT((!is_divisible::value)); // has_remainder DEFINE_INFIX_BINARY_TRAIT(has_remainder, %); X operator%(X, X); X operator%(X, Y); STATIC_ASSERT((has_remainder::value)); STATIC_ASSERT((has_remainder::value)); STATIC_ASSERT((!has_remainder::value)); STATIC_ASSERT((has_remainder::value)); STATIC_ASSERT((!has_remainder::value)); STATIC_ASSERT((!has_remainder::value)); STATIC_ASSERT((has_remainder::value)); STATIC_ASSERT((!has_remainder::value)); STATIC_ASSERT((!has_remainder::value)); // has_xor DEFINE_INFIX_BINARY_TRAIT(has_xor, ^); X operator^(X, X); X operator^(X, Y); STATIC_ASSERT((has_xor::value)); STATIC_ASSERT((has_xor::value)); STATIC_ASSERT((!has_xor::value)); STATIC_ASSERT((has_xor::value)); STATIC_ASSERT((!has_xor::value)); STATIC_ASSERT((!has_xor::value)); STATIC_ASSERT((has_xor::value)); STATIC_ASSERT((!has_xor::value)); STATIC_ASSERT((!has_xor::value)); // has_bitand DEFINE_INFIX_BINARY_TRAIT(has_bitand, &); X operator&(X, X); X operator&(X, Y); STATIC_ASSERT((has_bitand::value)); STATIC_ASSERT((has_bitand::value)); STATIC_ASSERT((!has_bitand::value)); STATIC_ASSERT((has_bitand::value)); STATIC_ASSERT((!has_bitand::value)); STATIC_ASSERT((!has_bitand::value)); STATIC_ASSERT((has_bitand::value)); STATIC_ASSERT((!has_bitand::value)); STATIC_ASSERT((!has_bitand::value)); // has_bitor DEFINE_INFIX_BINARY_TRAIT(has_bitor, |); X operator|(X, X); X operator|(X, Y); STATIC_ASSERT((has_bitor::value)); STATIC_ASSERT((has_bitor::value)); STATIC_ASSERT((!has_bitor::value)); STATIC_ASSERT((has_bitor::value)); STATIC_ASSERT((!has_bitor::value)); STATIC_ASSERT((!has_bitor::value)); STATIC_ASSERT((has_bitor::value)); STATIC_ASSERT((!has_bitor::value)); STATIC_ASSERT((!has_bitor::value)); // has_left_shift DEFINE_INFIX_BINARY_TRAIT(has_left_shift, <<); X operator<<(X, X); X operator<<(X, Y); STATIC_ASSERT((has_left_shift::value)); STATIC_ASSERT((has_left_shift::value)); STATIC_ASSERT((!has_left_shift::value)); STATIC_ASSERT((has_left_shift::value)); STATIC_ASSERT((!has_left_shift::value)); STATIC_ASSERT((!has_left_shift::value)); STATIC_ASSERT((has_left_shift::value)); STATIC_ASSERT((!has_left_shift::value)); STATIC_ASSERT((!has_left_shift::value)); // has_right_shift DEFINE_INFIX_BINARY_TRAIT(has_right_shift, >>); X operator>>(X, X); X operator>>(X, Y); STATIC_ASSERT((has_right_shift::value)); STATIC_ASSERT((has_right_shift::value)); STATIC_ASSERT((!has_right_shift::value)); STATIC_ASSERT((has_right_shift::value)); STATIC_ASSERT((!has_right_shift::value)); STATIC_ASSERT((!has_right_shift::value)); STATIC_ASSERT((has_right_shift::value)); STATIC_ASSERT((!has_right_shift::value)); STATIC_ASSERT((!has_right_shift::value)); // can_subscript STATIC_ASSERT((can_subscript::value)); STATIC_ASSERT((can_subscript::value)); STATIC_ASSERT((can_subscript::value)); STATIC_ASSERT((can_subscript::value)); STATIC_ASSERT((!can_subscript::value)); STATIC_ASSERT((can_subscript::value));