call_if_cxx14.cpp 2.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. // Copyright (C) 2008-2018 Lorenzo Caminiti
  2. // Distributed under the Boost Software License, Version 1.0 (see accompanying
  3. // file LICENSE_1_0.txt or a copy at http://www.boost.org/LICENSE_1_0.txt).
  4. // See: http://www.boost.org/doc/libs/release/libs/contract/doc/html/index.html
  5. #include <boost/contract/call_if.hpp>
  6. #include <type_traits>
  7. #include <iterator>
  8. #include <functional> // std::bind for generic lambdas.
  9. #include <vector>
  10. #include <list>
  11. #include <sstream>
  12. template<typename Iter>
  13. struct is_random_access_iterator : std::is_same<
  14. typename std::iterator_traits<Iter>::iterator_category,
  15. std::random_access_iterator_tag
  16. > {};
  17. template<typename Iter>
  18. struct is_bidirectional_iterator : std::is_same<
  19. typename std::iterator_traits<Iter>::iterator_category,
  20. std::bidirectional_iterator_tag
  21. > {};
  22. template<typename Iter>
  23. struct is_input_iterator : std::is_same<
  24. typename std::iterator_traits<Iter>::iterator_category,
  25. std::input_iterator_tag
  26. > {};
  27. //[call_if_cxx14
  28. template<typename Iter, typename Dist>
  29. void myadvance(Iter& i, Dist n) {
  30. Iter* p = &i; // So captures change actual pointed iterator value.
  31. boost::contract::call_if<is_random_access_iterator<Iter> >(
  32. std::bind([] (auto p, auto n) { // C++14 generic lambda.
  33. *p += n;
  34. }, p, n)
  35. ).template else_if<is_bidirectional_iterator<Iter> >(
  36. std::bind([] (auto p, auto n) {
  37. if(n >= 0) while(n--) ++*p;
  38. else while(n++) --*p;
  39. }, p, n)
  40. ).template else_if<is_input_iterator<Iter> >(
  41. std::bind([] (auto p, auto n) {
  42. while(n--) ++*p;
  43. }, p, n)
  44. ).else_(
  45. std::bind([] (auto false_) {
  46. static_assert(false_, "requires at least input iterator");
  47. }, std::false_type()) // Use constexpr value.
  48. );
  49. }
  50. //]
  51. struct x {}; // Test not an iterator (static_assert failure in else_ above).
  52. namespace std {
  53. template<>
  54. struct iterator_traits<x> {
  55. typedef void iterator_category;
  56. };
  57. }
  58. int main() {
  59. std::vector<char> v;
  60. v.push_back('a');
  61. v.push_back('b');
  62. v.push_back('c');
  63. v.push_back('d');
  64. std::vector<char>::iterator r = v.begin(); // Random iterator.
  65. myadvance(r, 1);
  66. assert(*r == 'b');
  67. std::list<char> l(v.begin(), v.end());
  68. std::list<char>::iterator b = l.begin(); // Bidirectional iterator.
  69. myadvance(b, 2);
  70. assert(*b == 'c');
  71. std::istringstream s("a b c d");
  72. std::istream_iterator<char> i(s);
  73. myadvance(i, 3);
  74. assert(*i == 'd');
  75. // x j;
  76. // myadvance(j, 0); // Error (correctly because x not even input iter).
  77. return 0;
  78. }