1// DR 339
2//
3// Test of the use of various assignment 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
34#ifdef __GXX_EXPERIMENTAL_CXX0X__
35#  define STATIC_ASSERT(Expr) static_assert(Expr, #Expr)
36#else
37#  define STATIC_ASSERT(Expr) int JOIN(a,__LINE__)[Expr? 1 : -1]
38#endif
39
40struct Y {
41  Y& operator=(Y&);
42};
43
44struct X {
45  X& operator=(Y);
46  X& operator+=(X);
47  X& operator-=(X);
48  X& operator*=(X);
49  X& operator/=(X);
50  X& operator%=(X);
51  X& operator^=(X);
52  X& operator&=(X);
53  X& operator|=(X);
54  X& operator<<=(X);
55  X& operator>>=(X);
56};
57struct Z { };
58
59// is_assignable
60DEFINE_INFIX_BINARY_TRAIT(is_assignable, =);
61STATIC_ASSERT((is_assignable<int>::value));
62STATIC_ASSERT((is_assignable<int, long>::value));
63STATIC_ASSERT((is_assignable<X>::value));
64STATIC_ASSERT((!is_assignable<int*, int>::value));
65STATIC_ASSERT((is_assignable<int*>::value));
66STATIC_ASSERT((is_assignable<X, Y>::value));
67STATIC_ASSERT((!is_assignable<X, Z>::value));
68STATIC_ASSERT((!is_assignable<Y>::value));
69STATIC_ASSERT((!is_assignable<const int, long>::value));
70
71// has_plus_assign
72DEFINE_INFIX_BINARY_TRAIT(has_plus_assign, +=);
73X& operator+=(X&, Y);
74STATIC_ASSERT((has_plus_assign<int>::value));
75STATIC_ASSERT((has_plus_assign<int, long>::value));
76STATIC_ASSERT((has_plus_assign<X>::value));
77STATIC_ASSERT((has_plus_assign<int*, int>::value));
78STATIC_ASSERT((!has_plus_assign<int*>::value));
79STATIC_ASSERT((has_plus_assign<X, Y>::value));
80STATIC_ASSERT((!has_plus_assign<X, Z>::value));
81STATIC_ASSERT((!has_plus_assign<Y>::value));
82STATIC_ASSERT((!has_plus_assign<const int, long>::value));
83
84// has_minus_assign
85DEFINE_INFIX_BINARY_TRAIT(has_minus_assign, -=);
86X& operator-=(X&, Y);
87STATIC_ASSERT((has_minus_assign<int>::value));
88STATIC_ASSERT((has_minus_assign<int, long>::value));
89STATIC_ASSERT((has_minus_assign<X>::value));
90STATIC_ASSERT((has_minus_assign<int*, int>::value));
91STATIC_ASSERT((!has_minus_assign<int*>::value));
92STATIC_ASSERT((has_minus_assign<X, Y>::value));
93STATIC_ASSERT((!has_minus_assign<X, Z>::value));
94STATIC_ASSERT((!has_minus_assign<Y>::value));
95STATIC_ASSERT((!has_minus_assign<int X::*>::value));
96STATIC_ASSERT((!has_minus_assign<const int, long>::value));
97
98// has_multiply_assign
99DEFINE_INFIX_BINARY_TRAIT(has_multiply_assign, *=);
100X& operator*=(X&, Y);
101STATIC_ASSERT((has_multiply_assign<int>::value));
102STATIC_ASSERT((has_multiply_assign<int, long>::value));
103STATIC_ASSERT((has_multiply_assign<X>::value));
104STATIC_ASSERT((!has_multiply_assign<int*, int>::value));
105STATIC_ASSERT((!has_multiply_assign<int*>::value));
106STATIC_ASSERT((has_multiply_assign<X, Y>::value));
107STATIC_ASSERT((!has_multiply_assign<X, Z>::value));
108STATIC_ASSERT((!has_multiply_assign<Y>::value));
109STATIC_ASSERT((!has_multiply_assign<int X::*>::value));
110STATIC_ASSERT((!has_multiply_assign<const int, long>::value));
111
112// has_divide_assign
113DEFINE_INFIX_BINARY_TRAIT(has_divide_assign, /=);
114X& operator/=(X&, Y);
115STATIC_ASSERT((has_divide_assign<int>::value));
116STATIC_ASSERT((has_divide_assign<int, long>::value));
117STATIC_ASSERT((has_divide_assign<X>::value));
118STATIC_ASSERT((!has_divide_assign<int*, int>::value));
119STATIC_ASSERT((!has_divide_assign<int*>::value));
120STATIC_ASSERT((has_divide_assign<X, Y>::value));
121STATIC_ASSERT((!has_divide_assign<X, Z>::value));
122STATIC_ASSERT((!has_divide_assign<Y>::value));
123STATIC_ASSERT((!has_divide_assign<int X::*>::value));
124
125// has_remainder_assign
126DEFINE_INFIX_BINARY_TRAIT(has_remainder_assign, %=);
127X& operator%=(X&, Y);
128STATIC_ASSERT((has_remainder_assign<int>::value));
129STATIC_ASSERT((has_remainder_assign<int, long>::value));
130STATIC_ASSERT((!has_remainder_assign<float>::value));
131STATIC_ASSERT((has_remainder_assign<X>::value));
132STATIC_ASSERT((!has_remainder_assign<int*, int>::value));
133STATIC_ASSERT((!has_remainder_assign<int*>::value));
134STATIC_ASSERT((has_remainder_assign<X, Y>::value));
135STATIC_ASSERT((!has_remainder_assign<X, Z>::value));
136STATIC_ASSERT((!has_remainder_assign<Y>::value));
137STATIC_ASSERT((!has_remainder_assign<int X::*>::value));
138
139// has_xor_assign
140DEFINE_INFIX_BINARY_TRAIT(has_xor_assign, ^=);
141X& operator^=(X&, Y);
142STATIC_ASSERT((has_xor_assign<int>::value));
143STATIC_ASSERT((has_xor_assign<int, long>::value));
144STATIC_ASSERT((!has_xor_assign<float>::value));
145STATIC_ASSERT((has_xor_assign<X>::value));
146STATIC_ASSERT((!has_xor_assign<int*, int>::value));
147STATIC_ASSERT((!has_xor_assign<int*>::value));
148STATIC_ASSERT((has_xor_assign<X, Y>::value));
149STATIC_ASSERT((!has_xor_assign<X, Z>::value));
150STATIC_ASSERT((!has_xor_assign<Y>::value));
151STATIC_ASSERT((!has_xor_assign<int X::*>::value));
152
153// has_bitand_assign
154DEFINE_INFIX_BINARY_TRAIT(has_bitand_assign, &=);
155X& operator&=(X&, Y);
156STATIC_ASSERT((has_bitand_assign<int>::value));
157STATIC_ASSERT((has_bitand_assign<int, long>::value));
158STATIC_ASSERT((!has_bitand_assign<float>::value));
159STATIC_ASSERT((has_bitand_assign<X>::value));
160STATIC_ASSERT((!has_bitand_assign<int*, int>::value));
161STATIC_ASSERT((!has_bitand_assign<int*>::value));
162STATIC_ASSERT((has_bitand_assign<X, Y>::value));
163STATIC_ASSERT((!has_bitand_assign<X, Z>::value));
164STATIC_ASSERT((!has_bitand_assign<Y>::value));
165STATIC_ASSERT((!has_bitand_assign<int X::*>::value));
166
167// has_bitor_assign
168DEFINE_INFIX_BINARY_TRAIT(has_bitor_assign, |=);
169X& operator|=(X&, Y);
170STATIC_ASSERT((has_bitor_assign<int>::value));
171STATIC_ASSERT((has_bitor_assign<int, long>::value));
172STATIC_ASSERT((!has_bitor_assign<float>::value));
173STATIC_ASSERT((has_bitor_assign<X>::value));
174STATIC_ASSERT((!has_bitor_assign<int*, int>::value));
175STATIC_ASSERT((!has_bitor_assign<int*>::value));
176STATIC_ASSERT((has_bitor_assign<X, Y>::value));
177STATIC_ASSERT((!has_bitor_assign<X, Z>::value));
178STATIC_ASSERT((!has_bitor_assign<Y>::value));
179STATIC_ASSERT((!has_bitor_assign<int X::*>::value));
180
181// has_left_shift_assign
182DEFINE_INFIX_BINARY_TRAIT(has_left_shift_assign, <<=);
183X& operator<<=(X&, Y);
184STATIC_ASSERT((has_left_shift_assign<int>::value));
185STATIC_ASSERT((has_left_shift_assign<int, long>::value));
186STATIC_ASSERT((!has_left_shift_assign<float>::value));
187STATIC_ASSERT((has_left_shift_assign<X>::value));
188STATIC_ASSERT((!has_left_shift_assign<int*, int>::value));
189STATIC_ASSERT((!has_left_shift_assign<int*>::value));
190STATIC_ASSERT((has_left_shift_assign<X, Y>::value));
191STATIC_ASSERT((!has_left_shift_assign<X, Z>::value));
192STATIC_ASSERT((!has_left_shift_assign<Y>::value));
193STATIC_ASSERT((!has_left_shift_assign<int X::*>::value));
194
195// has_right_shift_assign
196DEFINE_INFIX_BINARY_TRAIT(has_right_shift_assign, >>=);
197X& operator>>=(X&, Y);
198STATIC_ASSERT((has_right_shift_assign<int>::value));
199STATIC_ASSERT((has_right_shift_assign<int, long>::value));
200STATIC_ASSERT((!has_right_shift_assign<float>::value));
201STATIC_ASSERT((has_right_shift_assign<X>::value));
202STATIC_ASSERT((!has_right_shift_assign<int*, int>::value));
203STATIC_ASSERT((!has_right_shift_assign<int*>::value));
204STATIC_ASSERT((has_right_shift_assign<X, Y>::value));
205STATIC_ASSERT((!has_right_shift_assign<X, Z>::value));
206STATIC_ASSERT((!has_right_shift_assign<Y>::value));
207STATIC_ASSERT((!has_right_shift_assign<int X::*>::value));
208