1
2 // Copyright (C) 2008-2018 Lorenzo Caminiti
3 // Distributed under the Boost Software License, Version 1.0 (see accompanying
4 // file LICENSE_1_0.txt or a copy at http://www.boost.org/LICENSE_1_0.txt).
5 // See: http://www.boost.org/doc/libs/release/libs/contract/doc/html/index.html
6
7 #include <boost/config.hpp>
8 #ifdef BOOST_MSVC
9
10 // WARNING: MSVC (at least up to VS 2015) gives a compile-time error if SFINAE
11 // cannot introspect a member because of its private or protected access level.
12 // That is incorrect, SFINAE should fail in these cases without generating
13 // compile-time errors like GCC and CLang do. Therefore, currently it is not
14 // possible to override a member that is public in one base but private or
15 // protected in other base using this library on MSVC (that can be done instead
16 // using this library on GCC or CLang).
main()17 int main() { return 0; } // Trivial program for MSVC.
18
19 #else
20
21 #include <boost/contract.hpp>
22 #include <limits>
23 #include <cassert>
24
25 class counter {
26 // Virtual private and protected functions still declare extra
27 // `virtual_* = 0` parameter (otherwise they cannot be overridden).
28 protected:
set(int n,boost::contract::virtual_ * =0)29 virtual void set(int n, boost::contract::virtual_* = 0) {
30 boost::contract::check c = boost::contract::function()
31 .precondition([&] {
32 BOOST_CONTRACT_ASSERT(n <= 0);
33 })
34 .postcondition([&] {
35 BOOST_CONTRACT_ASSERT(get() == n);
36 })
37 ;
38
39 n_ = n;
40 }
41
42 private:
dec(boost::contract::virtual_ * =0)43 virtual void dec(boost::contract::virtual_* = 0) {
44 boost::contract::old_ptr<int> old_get = BOOST_CONTRACT_OLDOF(get());
45 boost::contract::check c = boost::contract::function()
46 .precondition([&] {
47 BOOST_CONTRACT_ASSERT(
48 get() + 1 >= std::numeric_limits<int>::min());
49 })
50 .postcondition([&] {
51 BOOST_CONTRACT_ASSERT(get() == *old_get - 1);
52 })
53 ;
54
55 set(get() - 1);
56 }
57
58 int n_;
59
60 public:
get(boost::contract::virtual_ * v=0) const61 virtual int get(boost::contract::virtual_* v = 0) const {
62 int result;
63 boost::contract::check c = boost::contract::public_function(
64 v, result, this)
65 .postcondition([&] (int const result) {
66 BOOST_CONTRACT_ASSERT(result <= 0);
67 BOOST_CONTRACT_ASSERT(result == n_);
68 })
69 ;
70
71 return result = n_;
72 }
73
counter()74 counter() : n_(0) {} // Should contract constructor and destructor too.
75
invariant() const76 void invariant() const {
77 BOOST_CONTRACT_ASSERT(get() <= 0);
78 }
79
80 friend int main();
81 };
82
83 //[private_protected_virtual_multi_countable
84 class countable {
85 public:
invariant() const86 void invariant() const {
87 BOOST_CONTRACT_ASSERT(get() <= 0);
88 }
89
90 virtual void dec(boost::contract::virtual_* v = 0) = 0;
91 virtual void set(int n, boost::contract::virtual_* v = 0) = 0;
92 virtual int get(boost::contract::virtual_* v = 0) const = 0;
93 };
94
95 /* ... */
96 //]
97
dec(boost::contract::virtual_ * v)98 void countable::dec(boost::contract::virtual_* v) {
99 boost::contract::old_ptr<int> old_get = BOOST_CONTRACT_OLDOF(v, get());
100 boost::contract::check c = boost::contract::public_function(v, this)
101 .precondition([&] {
102 BOOST_CONTRACT_ASSERT(get() > std::numeric_limits<int>::min());
103 })
104 .postcondition([&] {
105 BOOST_CONTRACT_ASSERT(get() < *old_get);
106 })
107 ;
108 assert(false); // Never executed by this library.
109 }
110
set(int n,boost::contract::virtual_ * v)111 void countable::set(int n, boost::contract::virtual_* v) {
112 boost::contract::check c = boost::contract::public_function(
113 v, this)
114 .precondition([&] {
115 BOOST_CONTRACT_ASSERT(n <= 0);
116 })
117 .postcondition([&] {
118 BOOST_CONTRACT_ASSERT(get() == n);
119 })
120 ;
121 assert(false); // Never executed by this library.
122 }
123
get(boost::contract::virtual_ * v) const124 int countable::get(boost::contract::virtual_* v) const {
125 int result;
126 boost::contract::check c = boost::contract::public_function(
127 v, result, this);
128 assert(false); // Never executed by this library.
129 }
130
131 //[private_protected_virtual_multi_counter10
132 class counter10
133 #define BASES public countable, public counter // Multiple inheritance.
134 : BASES
135 {
136 public:
137 typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types;
138 #undef BASES
139
140 // Overriding from public members from `countable` so use `override_...`.
141
set(int n,boost::contract::virtual_ * v=0)142 virtual void set(int n, boost::contract::virtual_* v = 0) /* override */ {
143 boost::contract::check c = boost::contract::public_function<
144 override_set>(v, &counter10::set, this, n)
145 .precondition([&] {
146 BOOST_CONTRACT_ASSERT(n % 10 == 0);
147 })
148 .postcondition([&] {
149 BOOST_CONTRACT_ASSERT(get() == n);
150 })
151 ;
152
153 counter::set(n);
154 }
155
dec(boost::contract::virtual_ * v=0)156 virtual void dec(boost::contract::virtual_* v = 0) /* override */ {
157 boost::contract::old_ptr<int> old_get = BOOST_CONTRACT_OLDOF(v, get());
158 boost::contract::check c = boost::contract::public_function<
159 override_dec>(v, &counter10::dec, this)
160 .precondition([&] {
161 BOOST_CONTRACT_ASSERT(
162 get() + 10 >= std::numeric_limits<int>::min());
163 })
164 .postcondition([&] {
165 BOOST_CONTRACT_ASSERT(get() == *old_get - 10);
166 })
167 ;
168
169 set(get() - 10);
170 }
171
BOOST_CONTRACT_OVERRIDES(set,dec)172 BOOST_CONTRACT_OVERRIDES(set, dec)
173
174 /* ... */
175 //]
176
177 virtual int get(boost::contract::virtual_* v = 0) const {
178 int result;
179 boost::contract::check c = boost::contract::public_function<
180 override_get>(v, result, &counter10::get, this);
181
182 return result = counter::get();
183 }
BOOST_CONTRACT_OVERRIDE(get)184 BOOST_CONTRACT_OVERRIDE(get)
185
186 // Should contract default constructor and destructor too.
187
188 void invariant() const {
189 BOOST_CONTRACT_ASSERT(get() % 10 == 0);
190 }
191 };
192
main()193 int main() {
194 counter cnt;
195 assert(cnt.get() == 0);
196 cnt.dec();
197 assert(cnt.get() == -1);
198
199 counter10 cnt10;
200 countable& b = cnt10; // Polymorphic calls.
201 assert(b.get() == 0);
202 b.dec();
203 assert(b.get() == -10);
204
205 return 0;
206 }
207
208 #endif // MSVC
209
210