// DR 339 // // Test of the use of various unary 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_PREFIX_UNARY_TRAIT(Name,Op) \ template \ typename enable_if<(sizeof(Op create_a(), 1) > 0), \ yes_type>::type \ JOIN(check_,Name)(int); \ \ template \ no_type JOIN(check_,Name)(...); \ \ template \ struct Name \ { \ static const bool value = \ (sizeof(JOIN(check_,Name)(0)) == sizeof(yes_type)); \ } #define DEFINE_POSTFIX_UNARY_TRAIT(Name,Op) \ template \ typename enable_if<(sizeof(create_a() Op, 1) > 0), \ yes_type>::type \ JOIN(check_,Name)(int); \ \ template \ no_type JOIN(check_,Name)(...); \ \ template \ struct Name \ { \ static const bool value = \ (sizeof(JOIN(check_,Name)(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 W { W operator+(); W operator-(); int operator*(); W operator~(); bool operator!(); W& operator++(); W& operator--(); W& operator++(int); W& operator--(int); }; struct X { }; X operator+(X); X operator-(X); int operator*(X); X operator~(X); bool operator!(X); X& operator++(X&); X& operator--(X&); X& operator++(X&, int); X& operator--(X&, int); struct Y { }; struct Z { private: Z operator+(); // { dg-error "is private" } Z operator-(); // { dg-error "is private" } int operator*(); // { dg-error "is private" } Z operator~(); // { dg-error "is private" } bool operator!(); // { dg-error "is private" } Z& operator++(); // { dg-error "is private" } Z& operator--(); // { dg-error "is private" } Z& operator++(int); // { dg-error "is private" } Z& operator--(int); // { dg-error "is private" } }; // has_unary_plus DEFINE_PREFIX_UNARY_TRAIT(has_unary_plus, +); // { dg-error "within this context" } STATIC_ASSERT((has_unary_plus::value)); STATIC_ASSERT((!has_unary_plus::value)); STATIC_ASSERT((has_unary_plus::value)); STATIC_ASSERT((has_unary_plus::value)); STATIC_ASSERT((!has_unary_plus::value)); // is_negatable DEFINE_PREFIX_UNARY_TRAIT(is_negatable, -); // { dg-error "within this context" } STATIC_ASSERT((is_negatable::value)); STATIC_ASSERT((!is_negatable::value)); STATIC_ASSERT((is_negatable::value)); STATIC_ASSERT((is_negatable::value)); STATIC_ASSERT((!is_negatable::value)); // is_dereferenceable DEFINE_PREFIX_UNARY_TRAIT(is_dereferenceable, *); // { dg-error "within this context" } STATIC_ASSERT((!is_dereferenceable::value)); STATIC_ASSERT((is_dereferenceable::value)); STATIC_ASSERT((is_dereferenceable::value)); STATIC_ASSERT((is_dereferenceable::value)); STATIC_ASSERT((!is_dereferenceable::value)); // has_bitwise_not DEFINE_PREFIX_UNARY_TRAIT(has_bitwise_not, ~); // { dg-error "within this context" } STATIC_ASSERT((has_bitwise_not::value)); STATIC_ASSERT((!has_bitwise_not::value)); STATIC_ASSERT((has_bitwise_not::value)); STATIC_ASSERT((has_bitwise_not::value)); STATIC_ASSERT((!has_bitwise_not::value)); // has_truth_not DEFINE_PREFIX_UNARY_TRAIT(has_truth_not, !); // { dg-error "within this context" } STATIC_ASSERT((has_truth_not::value)); STATIC_ASSERT((has_truth_not::value)); STATIC_ASSERT((has_truth_not::value)); STATIC_ASSERT((has_truth_not::value)); STATIC_ASSERT((!has_truth_not::value)); // has_preincrement DEFINE_PREFIX_UNARY_TRAIT(has_preincrement, ++); // { dg-error "within this context" } STATIC_ASSERT((has_preincrement::value)); STATIC_ASSERT((has_preincrement::value)); STATIC_ASSERT((!has_preincrement::value)); STATIC_ASSERT((has_preincrement::value)); STATIC_ASSERT((has_preincrement::value)); STATIC_ASSERT((!has_preincrement::value)); // has_predecrement DEFINE_PREFIX_UNARY_TRAIT(has_predecrement, --); // { dg-error "within this context" } STATIC_ASSERT((has_predecrement::value)); STATIC_ASSERT((has_predecrement::value)); STATIC_ASSERT((!has_predecrement::value)); STATIC_ASSERT((has_predecrement::value)); STATIC_ASSERT((has_predecrement::value)); STATIC_ASSERT((!has_predecrement::value)); // has_postincrement DEFINE_POSTFIX_UNARY_TRAIT(has_postincrement, ++); // { dg-error "within this context" } STATIC_ASSERT((has_postincrement::value)); STATIC_ASSERT((has_postincrement::value)); STATIC_ASSERT((!has_postincrement::value)); STATIC_ASSERT((has_postincrement::value)); STATIC_ASSERT((has_postincrement::value)); STATIC_ASSERT((!has_postincrement::value)); // has_postdecrement DEFINE_POSTFIX_UNARY_TRAIT(has_postdecrement, --); // { dg-error "within this context" } STATIC_ASSERT((has_postdecrement::value)); STATIC_ASSERT((has_postdecrement::value)); STATIC_ASSERT((!has_postdecrement::value)); STATIC_ASSERT((has_postdecrement::value)); STATIC_ASSERT((has_postdecrement::value)); STATIC_ASSERT((!has_postdecrement::value)); // Check for private members STATIC_ASSERT((has_unary_plus::value)); // { dg-message "required from here" } STATIC_ASSERT((is_negatable::value)); // { dg-message "required from here" } STATIC_ASSERT((is_dereferenceable::value)); // { dg-message "required from here" } STATIC_ASSERT((has_bitwise_not::value)); // { dg-message "required from here" } STATIC_ASSERT((has_truth_not::value)); // { dg-message "required from here" } STATIC_ASSERT((has_preincrement::value)); // { dg-message "required from here" } STATIC_ASSERT((has_predecrement::value)); // { dg-message "required from here" } STATIC_ASSERT((has_postincrement::value)); // { dg-message "required from here" } STATIC_ASSERT((has_postdecrement::value)); // { dg-message "required from here" }