1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
|
// Copyright (C) 2008-2018 Lorenzo Caminiti
// Distributed under the Boost Software License, Version 1.0 (see accompanying
// file LICENSE_1_0.txt or a copy at http://www.boost.org/LICENSE_1_0.txt).
// See: http://www.boost.org/doc/libs/release/libs/contract/doc/html/index.html
#include <boost/contract.hpp>
#include <boost/type_traits.hpp>
#include <boost/noncopyable.hpp>
#include <cassert>
//[old_if_copyable_offset
template<typename T> // T might or might not be copyable.
void offset(T& x, int count) {
// No compiler error if T has no copy constructor...
boost::contract::old_ptr_if_copyable<T> old_x = BOOST_CONTRACT_OLDOF(x);
boost::contract::check c = boost::contract::function()
.postcondition([&] {
// ...but old value null if T has no copy constructor.
if(old_x) BOOST_CONTRACT_ASSERT(x == *old_x + count);
})
;
x += count;
}
//]
//[old_if_copyable_w_decl
// Copyable type but...
class w {
public:
w(w const&) { /* Some very expensive copy operation here... */ }
/* ... */
//]
w() : num_(0) {}
int operator+(int i) const { return num_ + i; }
w& operator+=(int i) { num_ += i; return *this; }
bool operator==(int i) const { return long(num_) == i; }
private:
unsigned long num_;
};
//[old_if_copyable_w_spec
// ...never copy old values for type `w` (because its copy is too expensive).
namespace boost { namespace contract {
template<>
struct is_old_value_copyable<w> : boost::false_type {};
} }
//]
//[old_if_copyable_p_decl
// Non-copyable type but...
class p : private boost::noncopyable {
int* num_;
friend struct boost::contract::old_value_copy<p>;
/* ... */
//]
public:
p() : num_(new int(0)) {}
~p() { delete num_; }
int operator+(int i) const { return *num_ + i; }
p& operator+=(int i) { *num_ += i; return *this; }
bool operator==(int i) const { return *num_ == i; }
};
//[old_if_copyable_p_spec
// ...still copy old values for type `p` (using a deep copy).
namespace boost { namespace contract {
template<>
struct old_value_copy<p> {
explicit old_value_copy(p const& old) {
*old_.num_ = *old.num_; // Deep copy pointed value.
}
p const& old() const { return old_; }
private:
p old_;
};
template<>
struct is_old_value_copyable<p> : boost::true_type {};
} }
//]
//[old_if_copyable_n_decl
class n { // Do not want to use boost::noncopyable but...
int num_;
private:
n(n const&); // ...unimplemented private copy constructor (so non-copyable).
/* ... */
//]
public:
n() : num_(0) {}
int operator+(int i) const { return num_ + i; }
n& operator+=(int i) { num_ += i; return *this; }
bool operator==(int i) const { return num_ == i; }
};
//[old_if_copyable_n_spec
// Specialize `boost::is_copy_constructible` (no need for this on C++11).
namespace boost { namespace contract {
template<>
struct is_old_value_copyable<n> : boost::false_type {};
} }
//]
int main() {
int i = 0; // Copy constructor, copy and check old values.
offset(i, 3);
assert(i == 3);
w j; // Expensive copy constructor, so never copy or check old values.
offset(j, 3);
assert(j == 3);
p k; // No copy constructor, but still copy and check old values.
offset(k, 3);
assert(k == 3);
n h; // No copy constructor, no compiler error but no old value checks.
offset(h, 3);
assert(h == 3);
return 0;
}
|