operators.qbk 19 KB

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