1// DR 339
2//
3// Test of the use of various binary operators with SFINAE
4
5// Boilerplate helpers
6typedef char yes_type;
7struct no_type { char data[2]; };
8
9template<typename T> T create_a();
10template<typename T> struct type { };
11
12template<bool, typename T = void> struct enable_if { typedef T type; };
13template<typename T> struct enable_if<false, T> { };
14
15#define JOIN( X, Y ) DO_JOIN( X, Y )
16#define DO_JOIN( X, Y ) DO_JOIN2(X,Y)
17#define DO_JOIN2( X, Y ) X##Y
18
19#define DEFINE_INFIX_BINARY_TRAIT(Name,Op)				\
20template<typename T, typename U>					\
21  typename enable_if<(sizeof(create_a<T>() Op create_a<U>(), 1) > 0),	\
22		     yes_type>::type					\
23  JOIN(check_,Name)(type<T>, type<U>);		                        \
24									\
25no_type JOIN(check_,Name)(...);						\
26									\
27template<typename T, typename U = T>					\
28struct Name								\
29{									\
30  static const bool value =						\
31    (sizeof(JOIN(check_,Name)(type<T>(), type<U>())) == sizeof(yes_type)); \
32}
33
34template<typename T, typename U>
35  typename enable_if<(sizeof(create_a<T>()[create_a<U>()], 1) > 0),
36                     yes_type>::type
37  check_subscript(int);
38
39template<typename T, typename U>
40  no_type check_subscript(...);
41
42template<typename T, typename U>
43struct can_subscript
44{
45  static const bool value =
46    (sizeof(check_subscript<T, U>(0)) == sizeof(yes_type));
47};
48
49#ifdef __GXX_EXPERIMENTAL_CXX0X__
50#  define STATIC_ASSERT(Expr) static_assert(Expr, #Expr)
51#else
52#  define STATIC_ASSERT(Expr) int JOIN(a,__LINE__)[Expr? 1 : -1]
53#endif
54
55struct X { };
56struct Y { int operator[](X); };
57
58// is_addable
59DEFINE_INFIX_BINARY_TRAIT(is_addable, +);
60X operator+(X, X);
61X operator+(X, Y);
62STATIC_ASSERT((is_addable<int>::value));
63STATIC_ASSERT((is_addable<int, long>::value));
64STATIC_ASSERT((is_addable<X>::value));
65STATIC_ASSERT((is_addable<int*, int>::value));
66STATIC_ASSERT((!is_addable<int*>::value));
67STATIC_ASSERT((is_addable<X, Y>::value));
68STATIC_ASSERT((!is_addable<Y>::value));
69
70// is_subtractable
71DEFINE_INFIX_BINARY_TRAIT(is_subtractable, -);
72X operator-(X, X);
73X operator-(X, Y);
74STATIC_ASSERT((is_subtractable<int>::value));
75STATIC_ASSERT((is_subtractable<int, long>::value));
76STATIC_ASSERT((is_subtractable<X>::value));
77STATIC_ASSERT((is_subtractable<int*, int>::value));
78STATIC_ASSERT((is_subtractable<int*>::value));
79STATIC_ASSERT((is_subtractable<X, Y>::value));
80STATIC_ASSERT((!is_subtractable<Y>::value));
81STATIC_ASSERT((!is_subtractable<int X::*>::value));
82
83// is_multiplicable
84DEFINE_INFIX_BINARY_TRAIT(is_multiplicable, *);
85X operator*(X, X);
86X operator*(X, Y);
87STATIC_ASSERT((is_multiplicable<int>::value));
88STATIC_ASSERT((is_multiplicable<int, long>::value));
89STATIC_ASSERT((is_multiplicable<X>::value));
90STATIC_ASSERT((!is_multiplicable<int*, int>::value));
91STATIC_ASSERT((!is_multiplicable<int*>::value));
92STATIC_ASSERT((is_multiplicable<X, Y>::value));
93STATIC_ASSERT((!is_multiplicable<Y>::value));
94STATIC_ASSERT((!is_multiplicable<int X::*>::value));
95
96// is_divisible
97DEFINE_INFIX_BINARY_TRAIT(is_divisible, /);
98X operator/(X, X);
99X operator/(X, Y);
100STATIC_ASSERT((is_divisible<int>::value));
101STATIC_ASSERT((is_divisible<int, long>::value));
102STATIC_ASSERT((is_divisible<X>::value));
103STATIC_ASSERT((!is_divisible<int*, int>::value));
104STATIC_ASSERT((!is_divisible<int*>::value));
105STATIC_ASSERT((is_divisible<X, Y>::value));
106STATIC_ASSERT((!is_divisible<Y>::value));
107STATIC_ASSERT((!is_divisible<int X::*>::value));
108
109// has_remainder
110DEFINE_INFIX_BINARY_TRAIT(has_remainder, %);
111X operator%(X, X);
112X operator%(X, Y);
113STATIC_ASSERT((has_remainder<int>::value));
114STATIC_ASSERT((has_remainder<int, long>::value));
115STATIC_ASSERT((!has_remainder<float>::value));
116STATIC_ASSERT((has_remainder<X>::value));
117STATIC_ASSERT((!has_remainder<int*, int>::value));
118STATIC_ASSERT((!has_remainder<int*>::value));
119STATIC_ASSERT((has_remainder<X, Y>::value));
120STATIC_ASSERT((!has_remainder<Y>::value));
121STATIC_ASSERT((!has_remainder<int X::*>::value));
122
123// has_xor
124DEFINE_INFIX_BINARY_TRAIT(has_xor, ^);
125X operator^(X, X);
126X operator^(X, Y);
127STATIC_ASSERT((has_xor<int>::value));
128STATIC_ASSERT((has_xor<int, long>::value));
129STATIC_ASSERT((!has_xor<float>::value));
130STATIC_ASSERT((has_xor<X>::value));
131STATIC_ASSERT((!has_xor<int*, int>::value));
132STATIC_ASSERT((!has_xor<int*>::value));
133STATIC_ASSERT((has_xor<X, Y>::value));
134STATIC_ASSERT((!has_xor<Y>::value));
135STATIC_ASSERT((!has_xor<int X::*>::value));
136
137// has_bitand
138DEFINE_INFIX_BINARY_TRAIT(has_bitand, &);
139X operator&(X, X);
140X operator&(X, Y);
141STATIC_ASSERT((has_bitand<int>::value));
142STATIC_ASSERT((has_bitand<int, long>::value));
143STATIC_ASSERT((!has_bitand<float>::value));
144STATIC_ASSERT((has_bitand<X>::value));
145STATIC_ASSERT((!has_bitand<int*, int>::value));
146STATIC_ASSERT((!has_bitand<int*>::value));
147STATIC_ASSERT((has_bitand<X, Y>::value));
148STATIC_ASSERT((!has_bitand<Y>::value));
149STATIC_ASSERT((!has_bitand<int X::*>::value));
150
151// has_bitor
152DEFINE_INFIX_BINARY_TRAIT(has_bitor, |);
153X operator|(X, X);
154X operator|(X, Y);
155STATIC_ASSERT((has_bitor<int>::value));
156STATIC_ASSERT((has_bitor<int, long>::value));
157STATIC_ASSERT((!has_bitor<float>::value));
158STATIC_ASSERT((has_bitor<X>::value));
159STATIC_ASSERT((!has_bitor<int*, int>::value));
160STATIC_ASSERT((!has_bitor<int*>::value));
161STATIC_ASSERT((has_bitor<X, Y>::value));
162STATIC_ASSERT((!has_bitor<Y>::value));
163STATIC_ASSERT((!has_bitor<int X::*>::value));
164
165// has_left_shift
166DEFINE_INFIX_BINARY_TRAIT(has_left_shift, <<);
167X operator<<(X, X);
168X operator<<(X, Y);
169STATIC_ASSERT((has_left_shift<int>::value));
170STATIC_ASSERT((has_left_shift<int, long>::value));
171STATIC_ASSERT((!has_left_shift<float>::value));
172STATIC_ASSERT((has_left_shift<X>::value));
173STATIC_ASSERT((!has_left_shift<int*, int>::value));
174STATIC_ASSERT((!has_left_shift<int*>::value));
175STATIC_ASSERT((has_left_shift<X, Y>::value));
176STATIC_ASSERT((!has_left_shift<Y>::value));
177STATIC_ASSERT((!has_left_shift<int X::*>::value));
178
179// has_right_shift
180DEFINE_INFIX_BINARY_TRAIT(has_right_shift, >>);
181X operator>>(X, X);
182X operator>>(X, Y);
183STATIC_ASSERT((has_right_shift<int>::value));
184STATIC_ASSERT((has_right_shift<int, long>::value));
185STATIC_ASSERT((!has_right_shift<float>::value));
186STATIC_ASSERT((has_right_shift<X>::value));
187STATIC_ASSERT((!has_right_shift<int*, int>::value));
188STATIC_ASSERT((!has_right_shift<int*>::value));
189STATIC_ASSERT((has_right_shift<X, Y>::value));
190STATIC_ASSERT((!has_right_shift<Y>::value));
191STATIC_ASSERT((!has_right_shift<int X::*>::value));
192
193// can_subscript
194STATIC_ASSERT((can_subscript<int*, int>::value));
195STATIC_ASSERT((can_subscript<int, int*>::value));
196STATIC_ASSERT((can_subscript<int(&)[7], int>::value));
197STATIC_ASSERT((can_subscript<int, int(&)[7]>::value));
198STATIC_ASSERT((!can_subscript<X, Y>::value));
199STATIC_ASSERT((can_subscript<Y, X>::value));
200