]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/type_traits/doc/operators.qbk
bump version to 12.2.2-pve1
[ceph.git] / ceph / src / boost / libs / type_traits / doc / operators.qbk
1 [/
2 (C) Copyright 2011 Frederic Bron.
3 Distributed under the Boost Software License, Version 1.0.
4 (See accompanying file LICENSE_1_0.txt or copy at
5 http://www.boost.org/LICENSE_1_0.txt).
6 ]
7 [c++]
8 [def __binary_temp `< class Lhs, class Rhs=Lhs, class Ret=dont_care >`]
9 [def __prefix_temp `< class Rhs, class Ret=dont_care >`]
10 [def __postfix_temp `< class Lhs, class Ret=dont_care >`]
11
12 [section:operators Operator Type Traits]
13
14 [heading Introduction]
15
16 These traits are all /value traits/ inheriting from __integral_constant
17 and providing a simple `true` or `false` boolean `value` which reflects the fact
18 that given types can or cannot be used with given operators.
19
20 For example, `has_plus<int, double>::value` is a `bool`
21 which value is `true` because it is possible to add a `double` to an `int` like
22 in the following code:
23 ``
24 int i;
25 double d;
26 i+d;
27 ``
28 It is also possible to know if the result of the operator can be used as function argument
29 of a given type.
30 For example, `has_plus<int, double, float>::value` is `true`
31 because it is possible to add a `double` to an `int` and
32 the result (`double`) can be converted to a `float` argument like in the following code:
33 ``
34 void f(float) { };
35 int i;
36 double d;
37 f(i+d);
38 ``
39
40 [heading Example of application]
41
42 These traits can be useful to optimize the code for types supporting given operations.
43 For example a function `std::advance` that increases an iterator of a given number of steps
44 could be implemented as follows:
45
46 ``
47 #include <boost/type_traits/has_plus_assign.hpp>
48
49 namespace detail {
50 template < class Iterator, class Distance, bool has_plus_assign >
51 struct advance_impl;
52
53 // this is used if += exists (efficient)
54 template < class Iterator, class Distance >
55 struct advance_impl<Iterator, Distance, true> {
56 void operator()(Iterator &i, Distance n) {
57 i+=n;
58 }
59 };
60
61 // this is use if += does not exists (less efficient but cannot do better)
62 template < class Iterator, class Distance >
63 struct advance_impl<Iterator, Distance, false> {
64 void operator()(Iterator &i, Distance n) {
65 if (n>0) {
66 while (n--) ++i;
67 } else {
68 while (n++) --i;
69 }
70 }
71 };
72 } // namespace detail
73
74 template < class Iterator, class Distance >
75 inline void advance(Iterator &i, Distance n) {
76 detail::advance_impl< Iterator, Distance, ::boost::has_plus_assign<Iterator>::value >()(i, n);
77 }
78 ``
79
80 Then the compiler chooses the most efficient implementation according to the type's ability to perform `+=` operation:
81
82 ``
83 #include <iostream>
84
85 class with {
86 int m_i;
87 public:
88 with(int i=0) : m_i(i) { }
89 with &operator+=(int rhs) { m_i+=rhs; return *this; }
90 operator int const () { return m_i; }
91 };
92
93 class without {
94 int m_i;
95 public:
96 without(int i=0) : m_i(i) { }
97 without &operator++() { ++m_i; return *this; }
98 without &operator--() { --m_i; return *this; }
99 operator int const () { return m_i; }
100 };
101
102 int main() {
103 with i=0;
104 advance(i, 10); // uses +=
105 std::cout<<"with: "<<i<<'\n';
106 without j=0;
107 advance(j, 10); // uses ++
108 std::cout<<"without: "<<j<<'\n';
109 return 0;
110 }
111 ``
112
113 [heading Description]
114 The syntax is the following:
115 ``
116 template __prefix_temp has_op; // prefix operator
117 template __postfix_temp has_op; // postfix operator
118 template __binary_temp has_op; // binary operator
119 ``
120 where:
121
122 * op represents the operator name
123 * `Lhs` is the type used at the left hand side of `operator op`,
124 * `Rhs` is the type used at the right hand side of `operator op`,
125 * `Ret` is the type for which we want to know if the result of `operator op` can
126 be converted to.
127
128 The default behaviour (`Ret=dont_care`) is to not check for the return value of the
129 operator.
130 If `Ret` is different from the default `dont_care`, the return value is checked to be
131 convertible to `Ret`. Convertible to `Ret` means that the return value can be
132 used as argument to a function expecting `Ret`:
133 ``
134 void f(Ret);
135 Lhs lhs;
136 Rhs rhs;
137 f(lhs+rhs); // is valid if has_plus<Lhs, Rhs, Ret>::value==true
138 ``
139 If `Ret=void`, the return type is checked to be exactly `void`.
140
141 The following tables give the list of supported binary, prefix and postfix
142 operators.
143
144 [table Supported prefix operators
145 [[prefix operator] [trait name]]
146 [[`!`] [[link boost_typetraits.reference.has_logical_not `has_logical_not`] __prefix_temp]]
147 [[`+`] [[link boost_typetraits.reference.has_unary_plus `has_unary_plus`]]]
148 [[`-`] [[link boost_typetraits.reference.has_unary_minus `has_unary_minus`] and [link boost_typetraits.reference.has_negate `has_negate`]]]
149 [[`~`] [[link boost_typetraits.reference.has_complement `has_complement`]]]
150 [[`*`] [[link boost_typetraits.reference.has_dereference `has_dereference`]]]
151 [[`++`] [[link boost_typetraits.reference.has_pre_increment `has_pre_increment`]]]
152 [[`--`] [[link boost_typetraits.reference.has_pre_decrement `has_pre_decrement`]]]
153 ]
154
155 [table Supported postfix operators
156 [[postfix operator] [trait name]]
157 [[`++`] [[link boost_typetraits.reference.has_post_increment `has_post_increment`] __postfix_temp]]
158 [[`--`] [[link boost_typetraits.reference.has_post_decrement `has_post_decrement`]]]
159 ]
160
161 [table Supported binary operators
162 [[binary operator] [trait name]]
163 [[`+`] [[link boost_typetraits.reference.has_plus `has_plus`] __binary_temp]]
164 [[`-`] [[link boost_typetraits.reference.has_minus `has_minus`]]]
165 [[`*`] [[link boost_typetraits.reference.has_multiplies `has_multiplies`]]]
166 [[`/`] [[link boost_typetraits.reference.has_divides `has_divides`]]]
167 [[`%`] [[link boost_typetraits.reference.has_modulus `has_modulus`]]]
168 [[`+=`] [[link boost_typetraits.reference.has_plus_assign `has_plus_assign`]]]
169 [[`-=`] [[link boost_typetraits.reference.has_minus_assign `has_minus_assign`]]]
170 [[`*=`] [[link boost_typetraits.reference.has_multiplies_assign `has_multiplies_assign`]]]
171 [[`/=`] [[link boost_typetraits.reference.has_divides_assign `has_divides_assign`]]]
172 [[`%=`] [[link boost_typetraits.reference.has_modulus_assign `has_modulus_assign`]]]
173 [[`&`] [[link boost_typetraits.reference.has_bit_and `has_bit_and`]]]
174 [[`|`] [[link boost_typetraits.reference.has_bit_or `has_bit_or`]]]
175 [[`^`] [[link boost_typetraits.reference.has_bit_xor `has_bit_xor`]]]
176 [[`&=`] [[link boost_typetraits.reference.has_bit_and_assign `has_bit_and_assign`]]]
177 [[`|=`] [[link boost_typetraits.reference.has_bit_or_assign `has_bit_or_assign`]]]
178 [[`^=`] [[link boost_typetraits.reference.has_bit_xor_assign `has_bit_xor_assign`]]]
179 [[`<<`] [[link boost_typetraits.reference.has_left_shift `has_left_shift`]]]
180 [[`>>`] [[link boost_typetraits.reference.has_right_shift `has_right_shift`]]]
181 [[`<<=`] [[link boost_typetraits.reference.has_left_shift_assign `has_left_shift_assign`]]]
182 [[`>>=`] [[link boost_typetraits.reference.has_right_shift_assign `has_right_shift_assign`]]]
183 [[`==`] [[link boost_typetraits.reference.has_equal_to `has_equal_to`]]]
184 [[`!=`] [[link boost_typetraits.reference.has_not_equal_to `has_not_equal_to`]]]
185 [[`<`] [[link boost_typetraits.reference.has_less `has_less`]]]
186 [[`<=`] [[link boost_typetraits.reference.has_less_equal `has_less_equal`]]]
187 [[`>`] [[link boost_typetraits.reference.has_greater `has_greater`]]]
188 [[`>=`] [[link boost_typetraits.reference.has_greater_equal `has_greater_equal`]]]
189 [[`&&`] [[link boost_typetraits.reference.has_logical_and `has_logical_and`]]]
190 [[`||`] [[link boost_typetraits.reference.has_logical_or `has_logical_or`]]]
191 ]
192
193 The following operators are not supported because they could not be implemented using the same technique:
194 `operator=`, `operator->`, `operator&`, `operator[]`, `operator,`, `operator()`, `operator new`.
195
196
197 [heading cv qualifiers and references]
198
199 A reference sign `&` in the operator argument is ignored so that `has_plus< int&, double& >::value==has_plus< int, double >::value`.
200 This has been chosen because if the following code works (does not work):
201 ``
202 int i;
203 double d;
204 i+d;
205 ``
206 the following code also works (does not work):
207 ``
208 int &ir=i;
209 double &dr=d;
210 ir+dr;
211 ``
212
213 It was not possible to handle properly the `volatile` qualifier so that any construct using this qualifier has undefined behavior.
214
215 As a help, the following tables give the necessary conditions over each trait template argument for the trait `value` to be `true`.
216 They are non sufficient conditions because the conditions must be `true` for all arguments and return type for `value` to be `true`.
217
218 [table necessary and non sufficient condition on operator argument for value to be true
219 [[operator declaration] [`has_op< void >`] [`has_op< Arg >` and `has_op< Arg& >`] [`has_op< Arg const >` and `has_op< Arg const& >`]]
220 [[`operator`@`(Arg)`] [false] [true] [true]]
221 [[`operator`@`(Arg const)`] [false] [true] [true]]
222 [[`operator`@`(Arg &)`] [false] [true] [false]]
223 [[`operator`@`(Arg const &)`] [false] [true] [true]]
224 ]
225
226 [table necessary and non sufficient condition on operator return type for value to be true
227 [[operator declaration] [`has_op< ..., void >`] [`has_op< ..., Ret >`] [`has_op< ..., Ret const >`] [`has_op< ..., Ret & >`] [`has_op< ..., Ret const & >`]]
228 [[`void operator`@`(...)`] [true] [false] [false] [false] [false]]
229 [[`Ret operator`@`(...)`] [false] [true] [true] [false] [true]]
230 [[`Ret const operator`@`(...)`] [false] [true] [true] [false] [true]]
231 [[`Ret & operator`@`(...)`] [false] [true] [true] [true] [true]]
232 [[`Ret const & operator`@`(...)`] [false] [true] [true] [false] [true]]
233 ]
234
235
236 [heading Implementation]
237
238 The implementation consists in only header files.
239 The following headers should included first:
240 ``#include <boost/type_traits/has_operator.hpp>``
241 or
242 ``#include <boost/type_traits/has_op.hpp>``
243 where [^op] is the textual name chosen for the wanted operator.
244 The first method includes all operator traits.
245
246 All traits are implemented the same way using preprocessor macros to avoid code
247 duplication.
248 The main files are in [^boost/type_traits/detail]: [^has_binary_operator.hpp],
249 [^has_prefix_operator.hpp] and [^has_postfix_operator.hpp].
250 The example of prefix `operator-` is presented below:
251
252 ``
253 namespace boost {
254 namespace detail {
255
256 // This namespace ensures that argument-dependent name lookup does not mess things up.
257 namespace has_unary_minus_impl {
258
259 // 1. a function to have an instance of type T without requiring T to be default
260 // constructible
261 template <typename T> T &make();
262
263
264 // 2. we provide our operator definition for types that do not have one already
265
266 // a type returned from operator- when no such operator is
267 // found in the type's own namespace (our own operator is used) so that we have
268 // a means to know that our operator was used
269 struct no_operator { };
270
271 // this class allows implicit conversions and makes the following operator
272 // definition less-preferred than any other such operators that might be found
273 // via argument-dependent name lookup
274 struct any { template <class T> any(T const&); };
275
276 // when operator- is not available, this one is used
277 no_operator operator-(const any&);
278
279
280 // 3. checks if the operator returns void or not
281 // conditions: Rhs!=void
282
283 // we first redefine "operator," so that we have no compilation error if
284 // operator- returns void and we can use the return type of
285 // (-rhs, returns_void_t()) to deduce if operator- returns void or not:
286 // - operator- returns void -> (-rhs, returns_void_t()) returns returns_void_t
287 // - operator- returns !=void -> (-rhs, returns_void_t()) returns int
288 struct returns_void_t { };
289 template <typename T> int operator,(const T&, returns_void_t);
290 template <typename T> int operator,(const volatile T&, returns_void_t);
291
292 // this intermediate trait has member value of type bool:
293 // - value==true -> operator- returns void
294 // - value==false -> operator- does not return void
295 template < typename Rhs >
296 struct operator_returns_void {
297 // overloads of function returns_void make the difference
298 // yes_type and no_type have different size by construction
299 static ::boost::type_traits::yes_type returns_void(returns_void_t);
300 static ::boost::type_traits::no_type returns_void(int);
301 static const bool value = sizeof(::boost::type_traits::yes_type)==sizeof(returns_void((-make<Rhs>(),returns_void_t())));
302 };
303
304
305 // 4. checks if the return type is Ret or Ret==dont_care
306 // conditions: Rhs!=void
307
308 struct dont_care { };
309
310 template < typename Rhs, typename Ret, bool Returns_void >
311 struct operator_returns_Ret;
312
313 template < typename Rhs >
314 struct operator_returns_Ret < Rhs, dont_care, true > {
315 static const bool value = true;
316 };
317
318 template < typename Rhs >
319 struct operator_returns_Ret < Rhs, dont_care, false > {
320 static const bool value = true;
321 };
322
323 template < typename Rhs >
324 struct operator_returns_Ret < Rhs, void, true > {
325 static const bool value = true;
326 };
327
328 template < typename Rhs >
329 struct operator_returns_Ret < Rhs, void, false > {
330 static const bool value = false;
331 };
332
333 template < typename Rhs, typename Ret >
334 struct operator_returns_Ret < Rhs, Ret, true > {
335 static const bool value = false;
336 };
337
338 // otherwise checks if it is convertible to Ret using the sizeof trick
339 // based on overload resolution
340 // condition: Ret!=void and Ret!=dont_care and the operator does not return void
341 template < typename Rhs, typename Ret >
342 struct operator_returns_Ret < Rhs, Ret, false > {
343 static ::boost::type_traits::yes_type is_convertible_to_Ret(Ret); // this version is preferred for types convertible to Ret
344 static ::boost::type_traits::no_type is_convertible_to_Ret(...); // this version is used otherwise
345
346 static const bool value = sizeof(is_convertible_to_Ret(-make<Rhs>()))==sizeof(::boost::type_traits::yes_type);
347 };
348
349
350 // 5. checks for operator existence
351 // condition: Rhs!=void
352
353 // checks if our definition of operator- is used or an other
354 // existing one;
355 // this is done with redefinition of "operator," that returns no_operator or has_operator
356 struct has_operator { };
357 no_operator operator,(no_operator, has_operator);
358
359 template < typename Rhs >
360 struct operator_exists {
361 static ::boost::type_traits::yes_type check(has_operator); // this version is preferred when operator exists
362 static ::boost::type_traits::no_type check(no_operator); // this version is used otherwise
363
364 static const bool value = sizeof(check(((-make<Rhs>()),make<has_operator>())))==sizeof(::boost::type_traits::yes_type);
365 };
366
367
368 // 6. main trait: to avoid any compilation error, this class behaves
369 // differently when operator-(Rhs) is forbidden by the standard.
370 // Forbidden_if is a bool that is:
371 // - true when the operator-(Rhs) is forbidden by the standard
372 // (would yield compilation error if used)
373 // - false otherwise
374 template < typename Rhs, typename Ret, bool Forbidden_if >
375 struct trait_impl1;
376
377 template < typename Rhs, typename Ret >
378 struct trait_impl1 < Rhs, Ret, true > {
379 static const bool value = false;
380 };
381
382 template < typename Rhs, typename Ret >
383 struct trait_impl1 < Rhs, Ret, false > {
384 static const bool value =
385 ::boost::type_traits::ice_and<
386 operator_exists < Rhs >::value,
387 operator_returns_Ret < Rhs, Ret, operator_returns_void < Rhs >::value >::value
388 >::value
389 ;
390 };
391
392 // specialization needs to be declared for the special void case
393 template < typename Ret >
394 struct trait_impl1 < void, Ret, false > {
395 static const bool value = false;
396 };
397
398 // defines some typedef for convenience
399 template < typename Rhs, typename Ret >
400 struct trait_impl {
401 typedef typename ::boost::remove_reference<Rhs>::type Rhs_noref;
402 typedef typename ::boost::remove_cv<Rhs_noref>::type Rhs_nocv;
403 typedef typename ::boost::remove_cv< typename ::boost::remove_reference< typename ::boost::remove_pointer<Rhs_noref>::type >::type >::type Rhs_noptr;
404 static const bool value = trait_impl1 < Rhs_noref, Ret, ::boost::is_pointer< Rhs_noref >::value >::value;
405 };
406
407 } // namespace impl
408 } // namespace detail
409
410 // this is the accessible definition of the trait to end user
411 template < typename Rhs, typename Ret=::boost::detail::has_unary_minus_impl::dont_care >
412 struct has_unary_minus : ::boost::integral_constant<bool,(::boost::detail::has_unary_minus_impl::trait_impl < Rhs, Ret >::value)> { };
413
414 } // namespace boost
415 ``
416
417 [heading Limitation]
418
419 * Requires a compiler with working SFINAE.
420
421 [heading Known issues]
422
423 * These traits cannot detect whether the operators are public or not:
424 if an operator is defined as a private member of type `T` then
425 the instantiation of the corresponding trait will produce a compiler error.
426 For this reason these traits cannot be used to determine whether a type has a
427 public operator or not.
428 ``
429 struct A { private: A operator-(); };
430 boost::has_unary_minus<A>::value; // error: A::operator-() is private
431 ``
432
433 * There is an issue if the operator exists only for type `A` and `B` is
434 convertible to `A`. In this case, the compiler will report an ambiguous overload
435 because both the existing operator and the one we provide (with argument of type
436 `any`) need type conversion, so that none is preferred.
437 ``
438 struct A { };
439 void operator-(const A&);
440 struct B { operator A(); };
441 boost::has_unary_minus<A>::value; // this is fine
442 boost::has_unary_minus<B>::value; // error: ambiguous overload between
443 // operator-(const any&) and
444 // operator-(const A&)
445 // both need type conversion
446 ``
447 ``
448 struct B { };
449 struct A { A(const B&) { } };
450 void operator-(const A&);
451 boost::has_unary_minus<A>::value; // this is fine
452 boost::has_unary_minus<B>::value; // error: ambiguous overload between
453 // operator-(const any&) and
454 // operator-(const A&)
455 // both need type conversion
456 ``
457
458 * There is an issue when applying these traits to template classes.
459 If the operator is defined but does not bind for a given template type,
460 it is still detected by the trait which returns `true` instead of `false`.
461 This applies in particular to the containers of the standard library and `operator==`.
462 Example:
463 ``
464 #include <boost/type_traits/has_equal_to.hpp>
465 #include <iostream>
466
467 template <class T>
468 struct contains { T data; };
469
470 template <class T>
471 bool operator==(const contains<T> &lhs, const contains<T> &rhs) {
472 return f(lhs.data, rhs.data);
473 }
474
475 class bad { };
476 class good { };
477 bool f(const good&, const good&) { }
478
479 int main() {
480 std::cout<<std::boolalpha;
481 // works fine for contains<good>
482 std::cout<<boost::has_equal_to< contains< good > >::value<<'\n'; // true
483 contains<good> g;
484 g==g; // ok
485 // does not work for contains<bad>
486 std::cout<<boost::has_equal_to< contains< bad > >::value<<'\n'; // true, should be false
487 contains<bad> b;
488 b==b; // compile time error
489 return 0;
490 }
491 ``
492
493 * `volatile` qualifier is not properly handled and would lead to undefined behavior
494
495
496 [heading Acknowledgments]
497
498 Frederic Bron is very thankful to numerous people from the boost mailing list for their kind help and patience.
499 In particular, the following persons have been very helpful for the implementation: Edward Diener, Eric Niebler, Jeffrey Lee Hellrung (Jr.), Robert Stewart, Roman Perepelitsa, Steven Watanabe, Vicente Botet.
500
501 [endsect]
502