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 Friend this class to declare invariants and base types as private members.
47 
48 Declare this class a friend of the user-defined class specifying the contracts
49 in order to declare the invariant functions and the base types @c typedef as
50 non-public members:
51 
52 @code
53 class u :
54     #define BASES public b, private w
55     BASES
56 {
57     friend class boost::contract::access;
58 
59     typedef BOOST_CONTRACT_BASES(BASES) base_types; // Private.
60     #undef BASES
61 
62     void invariant() const { ... } // Private.
63 
64 public:
65     ...
66 };
67 @endcode
68 
69 In real code, programmers will likely chose to declare this class as friend so
70 to fully control public interfaces of their user-defined classes.
71 This class is not intended to be directly used by programmers a part from
72 declaring it @c friend (and that is why this class does not have any public
73 member and it is not copyable).
74 
75 @warning    Not declaring this class friend of user-defined classes will cause
76             compiler errors on some compilers (e.g., MSVC) because the private
77             members needed to check the contracts will not be accessible.
78             On other compilers (e.g., GCC and CLang), the private access will
79             instead fail SFINAE and no compiler error will be reported while
80             invariants and subcontracting will be silently skipped at run-time.
81             Therefore, programmers must make sure to either declare this class
82             as friend (preferred) or to always declare invariant functions and
83             base types @c typedef as public members.
84 
85 @see @RefSect{advanced.access_specifiers, Access Specifiers}
86 */
87 class access { // Non-copyable (see below).
88 /** @cond */
89 private: // No public APIs (so users cannot use it directly by mistake).
90 
91     access(); // Should never be constructed (not even internally).
92     ~access();
93 
94     // No boost::noncopyable to avoid its overhead when contracts disabled.
95     access(access&);
96     access& operator=(access&);
97 
98     #if !defined(BOOST_CONTRACT_NO_CONDITIONS) || \
99             defined(BOOST_CONTRACT_STATIC_LINK)
100         BOOST_CONTRACT_DETAIL_MIRROR_HAS_TYPE(has_base_types,
101                 BOOST_CONTRACT_BASES_TYPEDEF)
102 
103         template<class C>
104         struct base_types_of {
105             typedef typename C::BOOST_CONTRACT_BASES_TYPEDEF type;
106         };
107     #endif
108 
109     #ifndef BOOST_CONTRACT_NO_INVARIANTS
110         BOOST_CONTRACT_DETAIL_MIRROR_HAS_MEMBER_FUNCTION(
111                 has_static_invariant_f, BOOST_CONTRACT_STATIC_INVARIANT_FUNC)
112 
113         BOOST_CONTRACT_DETAIL_MIRROR_HAS_STATIC_MEMBER_FUNCTION(
114                 has_static_invariant_s, BOOST_CONTRACT_STATIC_INVARIANT_FUNC)
115 
116         template<class C>
117         struct has_static_invariant : has_static_invariant_s<C, void,
118                 boost::mpl::vector<> > {};
119 
120         template<class C>
static_invariant()121         static void static_invariant() {
122             C::BOOST_CONTRACT_STATIC_INVARIANT_FUNC();
123         }
124 
125         template<class C>
126         class static_invariant_addr { // Class so to pass it as tparam.
127             typedef void (*func_ptr)();
128         public:
apply()129             static func_ptr apply() {
130                 return &C::BOOST_CONTRACT_STATIC_INVARIANT_FUNC;
131             }
132         };
133 
134         BOOST_CONTRACT_DETAIL_MIRROR_HAS_MEMBER_FUNCTION(
135                 has_invariant_f, BOOST_CONTRACT_INVARIANT_FUNC)
136 
137         BOOST_CONTRACT_DETAIL_MIRROR_HAS_STATIC_MEMBER_FUNCTION(
138                 has_invariant_s, BOOST_CONTRACT_INVARIANT_FUNC)
139 
140         template<class C>
141         struct has_cv_invariant : has_invariant_f<C, void, boost::mpl::vector<>,
142                 boost::function_types::cv_qualified> {};
143 
144         template<class C>
145         struct has_const_invariant : has_invariant_f<C, void, boost::mpl::
146                 vector<>, boost::function_types::const_qualified> {};
147 
148         template<class C>
cv_invariant(C const volatile * obj)149         static void cv_invariant(C const volatile* obj) {
150             BOOST_CONTRACT_DETAIL_DEBUG(obj);
151             obj->BOOST_CONTRACT_INVARIANT_FUNC();
152         }
153 
154         template<class C>
const_invariant(C const * obj)155         static void const_invariant(C const* obj) {
156             BOOST_CONTRACT_DETAIL_DEBUG(obj);
157             obj->BOOST_CONTRACT_INVARIANT_FUNC();
158         }
159     #endif
160 
161     // Friends (used to limit library's public API).
162     // NOTE: Using friends here and in all other places in this library
163     // does not increase compilation times (I experimented replacing all
164     // friends with public and got the same compilation times).
165     #if !defined(BOOST_CONTRACT_NO_CONDITIONS) || \
166             defined(BOOST_CONTRACT_STATIC_LINK)
167         BOOST_CONTRACT_DETAIL_DECL_DETAIL_COND_SUBCONTRACTING_Z(1,
168                 /* is_friend = */ 1, OO, RR, FF, CC, AArgs);
169 
170         BOOST_CONTRACT_DETAIL_DECL_FRIEND_OVERRIDING_PUBLIC_FUNCTIONS_Z(1,
171                 OO, RR, FF, CC, AArgs, vv, rr, ff, oobj, aargs)
172     #endif
173     #ifndef BOOST_CONTRACT_NO_INVARIANTS
174         template<typename RR, class CC>
175         friend class boost::contract::detail::cond_inv;
176     #endif
177 /** @endcond */
178 };
179 
180 } } // namespace
181 
182 #endif // #include guard
183 
184