1 
2 #ifndef BOOST_CONTRACT_ACCESS_HPP_
3 #define BOOST_CONTRACT_ACCESS_HPP_
4 
5 // Copyright (C) 2008-2018 Lorenzo Caminiti
6 // Distributed under the Boost Software License, Version 1.0 (see accompanying
7 // file LICENSE_1_0.txt or a copy at http://www.boost.org/LICENSE_1_0.txt).
8 // See: http://www.boost.org/doc/libs/release/libs/contract/doc/html/index.html
9 
10 /** @file
11 Allow to declare invariants, base types, etc all as private members.
12 */
13 
14 // IMPORTANT: Included by contract_macro.hpp so must #if-guard all its includes.
15 #include <boost/contract/core/config.hpp>
16 #if !defined(BOOST_CONTRACT_NO_CONDITIONS) || \
17         defined(BOOST_CONTRACT_STATIC_LINK)
18     #include <boost/contract/detail/decl.hpp>
19     #include <boost/contract/detail/type_traits/mirror.hpp>
20 #endif
21 #ifndef BOOST_CONTRACT_NO_INVARIANTS
22     #include <boost/contract/detail/debug.hpp>
23     #include <boost/function_types/property_tags.hpp>
24     #include <boost/mpl/vector.hpp>
25 #endif
26 
27 namespace boost { namespace contract {
28 
29 #if !defined(BOOST_CONTRACT_NO_CONDITIONS) || \
30         defined(BOOST_CONTRACT_STATIC_LINK)
31     class virtual_;
32 
33     namespace detail {
34         BOOST_CONTRACT_DETAIL_DECL_DETAIL_COND_SUBCONTRACTING_Z(1,
35                 /* is_friend = */ 0, OO, RR, FF, CC, AArgs);
36     }
37 #endif
38 #ifndef BOOST_CONTRACT_NO_INVARIANTS
39     namespace detail {
40         template<typename RR, class CC>
41         class cond_inv;
42     }
43 #endif
44 
45 /**
46 Declare this class as friend to program invariants and base types as private
47 members.
48 
49 Declare this class a friend of the user-defined class specifying the contracts
50 and then invariant functions and the base types @c typedef can be declared as
51 non-public members:
52 
53 @code
54 class u
55     #define BASES public b, private w
56     : BASES
57 {
58     friend class boost::contract::access;
59 
60     typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types; // Private.
61     #undef BASES
62 
63     void invariant() const { ... } // Private (same for static and volatile).
64 
65 public:
66     ...
67 };
68 @endcode
69 
70 In real code, programmers will likely chose to declare this class as friend so
71 to fully control public interfaces of their user-defined classes (this is not
72 extensively done in the examples of this documentation only for brevity).
73 This class is not intended to be directly used by programmers a part from
74 being declared as @c friend (and that is why this class does not have any public
75 member and it is not copyable).
76 
77 @warning    Not declaring this class friend of user-defined classes will cause
78             compiler errors on some compilers (e.g., MSVC) because the private
79             members needed to check the contracts will not be accessible.
80             On other compilers (e.g., GCC and CLang), the private access will
81             instead fail SFINAE and no compiler error will be reported while
82             invariants and subcontracting will be silently skipped at run-time.
83             Therefore, programmers must make sure to either declare this class
84             as friend or to always declare invariant functions and base types
85             @c typedef as public members.
86 
87 @see @RefSect{advanced.access_specifiers, Access Specifiers}
88 */
89 class access { // Non-copyable (see below).
90 /** @cond */
91 private: // No public APIs (so users cannot use it directly by mistake).
92 
93     access(); // Should never be constructed (not even internally).
94     ~access();
95 
96     // No boost::noncopyable to avoid its overhead when contracts disabled.
97     access(access&);
98     access& operator=(access&);
99 
100     #if !defined(BOOST_CONTRACT_NO_CONDITIONS) || \
101             defined(BOOST_CONTRACT_STATIC_LINK)
102         BOOST_CONTRACT_DETAIL_MIRROR_HAS_TYPE(has_base_types,
103                 BOOST_CONTRACT_BASES_TYPEDEF)
104 
105         template<class C>
106         struct base_types_of {
107             typedef typename C::BOOST_CONTRACT_BASES_TYPEDEF type;
108         };
109     #endif
110 
111     #ifndef BOOST_CONTRACT_NO_INVARIANTS
112         BOOST_CONTRACT_DETAIL_MIRROR_HAS_MEMBER_FUNCTION(
113                 has_static_invariant_f, BOOST_CONTRACT_STATIC_INVARIANT_FUNC)
114 
115         BOOST_CONTRACT_DETAIL_MIRROR_HAS_STATIC_MEMBER_FUNCTION(
116                 has_static_invariant_s, BOOST_CONTRACT_STATIC_INVARIANT_FUNC)
117 
118         template<class C>
119         struct has_static_invariant : has_static_invariant_s<C, void,
120                 boost::mpl::vector<> > {};
121 
122         template<class C>
static_invariant()123         static void static_invariant() {
124             C::BOOST_CONTRACT_STATIC_INVARIANT_FUNC();
125         }
126 
127         template<class C>
128         class static_invariant_addr { // Class so to pass it as tparam.
129             typedef void (*func_ptr)();
130         public:
apply()131             static func_ptr apply() {
132                 return &C::BOOST_CONTRACT_STATIC_INVARIANT_FUNC;
133             }
134         };
135 
136         BOOST_CONTRACT_DETAIL_MIRROR_HAS_MEMBER_FUNCTION(
137                 has_invariant_f, BOOST_CONTRACT_INVARIANT_FUNC)
138 
139         BOOST_CONTRACT_DETAIL_MIRROR_HAS_STATIC_MEMBER_FUNCTION(
140                 has_invariant_s, BOOST_CONTRACT_INVARIANT_FUNC)
141 
142         template<class C>
143         struct has_cv_invariant : has_invariant_f<C, void, boost::mpl::vector<>,
144                 boost::function_types::cv_qualified> {};
145 
146         template<class C>
147         struct has_const_invariant : has_invariant_f<C, void, boost::mpl::
148                 vector<>, boost::function_types::const_qualified> {};
149 
150         template<class C>
cv_invariant(C const volatile * obj)151         static void cv_invariant(C const volatile* obj) {
152             BOOST_CONTRACT_DETAIL_DEBUG(obj);
153             obj->BOOST_CONTRACT_INVARIANT_FUNC();
154         }
155 
156         template<class C>
const_invariant(C const * obj)157         static void const_invariant(C const* obj) {
158             BOOST_CONTRACT_DETAIL_DEBUG(obj);
159             obj->BOOST_CONTRACT_INVARIANT_FUNC();
160         }
161     #endif
162 
163     // Friends (used to limit library's public API).
164     // NOTE: Using friends here and in all other places in this library
165     // does not increase compilation times (I experimented replacing all
166     // friends with public and got the same compilation times).
167     #if !defined(BOOST_CONTRACT_NO_CONDITIONS) || \
168             defined(BOOST_CONTRACT_STATIC_LINK)
169         BOOST_CONTRACT_DETAIL_DECL_DETAIL_COND_SUBCONTRACTING_Z(1,
170                 /* is_friend = */ 1, OO, RR, FF, CC, AArgs);
171 
172         BOOST_CONTRACT_DETAIL_DECL_FRIEND_OVERRIDING_PUBLIC_FUNCTIONS_Z(1,
173                 OO, RR, FF, CC, AArgs, vv, rr, ff, oobj, aargs)
174     #endif
175     #ifndef BOOST_CONTRACT_NO_INVARIANTS
176         template<typename RR, class CC>
177         friend class boost::contract::detail::cond_inv;
178     #endif
179 /** @endcond */
180 };
181 
182 } } // namespace
183 
184 #endif // #include guard
185 
186