diff --git a/doc/Jamfile.v2 b/doc/Jamfile.v2 index 026eb52..84e90e1 100644 --- a/doc/Jamfile.v2 +++ b/doc/Jamfile.v2 @@ -9,23 +9,27 @@ using boostbook ; doxygen reference : + ../include/boost/contract.hpp + ../include/boost/contract_macro.hpp + + ../include/boost/contract/assert.hpp + ../include/boost/contract/base_types.hpp + ../include/boost/contract/call_if.hpp + ../include/boost/contract/check.hpp ../include/boost/contract/constructor.hpp ../include/boost/contract/destructor.hpp - ../include/boost/contract/public_function.hpp ../include/boost/contract/function.hpp - ../include/boost/contract/base_types.hpp - ../include/boost/contract/override.hpp - ../include/boost/contract/check.hpp - ../include/boost/contract/assert.hpp ../include/boost/contract/old.hpp - ../include/boost/contract/call_if.hpp + ../include/boost/contract/override.hpp + ../include/boost/contract/public_function.hpp - ../include/boost/contract/core/specify.hpp ../include/boost/contract/core/access.hpp - ../include/boost/contract/core/virtual.hpp + ../include/boost/contract/core/check_macro.hpp ../include/boost/contract/core/config.hpp - - ../include/boost/contract.hpp + ../include/boost/contract/core/constructor_precondition.hpp + ../include/boost/contract/core/exception.hpp + ../include/boost/contract/core/specify.hpp + ../include/boost/contract/core/virtual.hpp : "Reference" # Quickbook's Doxygen does not show destructor exception specs. @@ -53,5 +57,6 @@ boostbook doc : contract boost.root=../../ admon.graphics.path=../../doc/src/images/ html.stylesheet=../../doc/src/boostbook.css + toc.max.depth=1 ; diff --git a/doc/advanced_topics.qbk b/doc/advanced_topics.qbk index 645f7b1..da650a2 100644 --- a/doc/advanced_topics.qbk +++ b/doc/advanced_topics.qbk @@ -8,22 +8,53 @@ This section illustrates more advanced uses of this library. +[section Pure Virtual Public Functions] + +In C++, pure virtual functions are allowed to have a /default implementation/ as long as such implementation is programmed out-of-line so defined outside the class declaring the `virtual ... = 0;` pure virtual function. + +Contracts for pure virtual public functions are programmed using the [funcref boost::contract::public_function] function like for (non-pure) virtual public functions (all consideration made in __Virtual_Public_Functions__ apply). +However, contracts have to be programmed out-of-line, in the default implementation of the pure virtual function. +For example (see also [@../../example/features/pure_virtual_public.cpp =pure_virtual_public.cpp=]): + +[import ../example/features/pure_virtual_public.cpp] +[pure_virtual_public_base] +[pure_virtual_public_impl] +[pure_virtual_public_derived] + +This library will never actually execute the pure virtual function body while it is calling the pure virtual function default implementation to check contracts for subcontracting. +Therefore, programmers can safely `assert(false)` at the beginning of the body if they intend for that body to never be executed (or they can program a working body in case they need to use C++ pure virtual function default implementation outside of what strictly required by this library). + +[import ../example/features/named_override.cpp] +[note +As seen in __Public_Function_Overrides__, preconditions of overriding public functions are checked in __OR__ with preconditions of overridden virtual public functions. +Therefore, if a virtual public function in a base class specifies no precondition then preconditions specified by all its overriding functions in derived classes will have no effect (because when checked in __OR__ with the overridden function from the base class that has no preconditions, they will always pass). +This correctly reflects the fact that the overridden function in the base class can be called from any context (because it has no precondition) and so must all its overriding functions in all derived classes in accordance with the __substitution_principle__. + +That said, it is sometimes useful for a base class to declare a pure virtual function with a single precondition `BOOST_CONTRACT_ASSERT(false)` that will always fail. +This indicates that the pure virtual function can never be called unless it is redefined in a derived class (which is always the case with C++ pure virtual functions) and also that the base class designer has intentionally left it up to derived classes to specify preconditions for the pure virtual function in question. +This technique makes sense only for preconditions of pure virtual public functions (otherwise `BOOST_CONTRACT_ASSERT(false)` will prevent calling virtual public functions in concrete bases). +For example (see also [@../../example/features/named_override.cpp =named_override.cpp=]): + +[named_override_pure_virtual_assert_false] +] + +[endsect] + [section Optional Return Value] -It is possible to use `boost::optional` to handle the return value when programmers cannot construct the result variable at its point of declaration before the contract (e.g., because an appropriate constructor for the return type is not available at that point, or just because it would be too expensive to execute an extra initialization of the return value at run-time). +It is possible to use `boost::optional` to handle return values when programmers cannot construct the result variable at its point of declaration before the contract (e.g., because an appropriate constructor for the return type is not available at that point, or just because it would be too expensive to execute an extra initialization of the return value at run-time). [footnote *Rationale:* -`boost::optional` is used instead of `std::optional` because this library is designed to work well with Boost and because `std::optional` is not part of the C++ standard yet. +`boost::optional` is used instead of `std::optional` because `std::optional` is not part of C++ standards prior to C++17. ] For example (see also [@../../example/features/optional_result.cpp =optional_result.cpp=]): [import ../example/features/optional_result.cpp] [optional_result] -In this example the return type `surface` does not have a default constructor that can be used to initialize `result` when it is declared before the contract. -The `surface` non-default constructor is not used to initialize `result` by passing it `edge * edge` and `edge * 4` because such operations are logically the responsibility of the function body (e.g., it makes logical sense to do such multiplications only after `edge` has been checked to be positive by the preconditions). -Therefore, instead of initializing `result` with some arbitrary `area` and `perimeter` values (e.g., `0` and `0`), `boost::optional` is used in this example to not initialize `result` with a return value when it is declared before the contract. -`result` is initialized later in the function body when the function is about to return and directly using the correct return value `result = surface(edge * edge, edge * 4)`. +In this example the return type is a reference so it does not have default constructor that can be used to initialize `result` when it is declared before the contract declaration. +In addition, `Index` needs to be validated to be smaller than `size()` by the precondition before it can be used to retrieve the reference to be assigned to `result` so `vect[Index]` cannot be used either to initialize `result` when it is declared before the contract declaration. +Therefore, `boost::optional` is used to defer `result` proper initialization until the execution of the function body after the contract declaration when `Index` has been validated by the preconditions and `vect[Index]` can be safely evaluated to initialize `result`. As seen in __Return_Value__, it is the responsibility of the programmers to ensure that `result` is always set to the return value when the function exits without trowing an exception. This also ensures that `result` is always set before the postconditions are checked so programmers can always dereference `result` in postconditions to access the return value (using `operator*` and `operator->` as usual with `boost::optional`, and without having to explicitly check if `result` is an empty `boost::optional` object). @@ -33,15 +64,15 @@ This can be easily done by making sure that /all/ return statements in the funct ... return *(result = ...); // Assign `result` at each return. -[heading Virtual Public Functions and Public Function Overrides] +[heading Virtual Public Functions] -Similarly, `boost::optional` can be used to handle the return value passed to contracts of virtual public functions and public function overrides. -As seen in __Virtual_Public_Functions__ and __Public_Function_Overrides__, in these cases the return value `result` must be passed as a parameter to [funcref boost::contract::public_function] right after the [classref boost::contract::virtual_]`*` parameter `v`. +Similarly, `boost::optional` can be used to handle the return value passed to contracts of virtual public functions (pure or not) and of public function overrides. +As seen in __Pure_Virtual_Public_Functions__, __Virtual_Public_Functions__, and __Public_Function_Overrides__, in these cases the return value `result` must be passed as a parameter to [funcref boost::contract::public_function] right after the parameter `v` of type [classref boost::contract::virtual_]`*`. Then the functor passed to `.postcondition(...)` takes one single parameter of type `boost::optional<`[^['result-type]]` const&> const&`. -For example (see also __Pure_Virtual_Public_Functions__ and [@../../example/features/pure_virtual_public.cpp =pure_virtual_public.cpp=]): +For example (see also [@../../example/features/optional_result_virtual.cpp =optional_result_virtual.cpp=]): -[import ../example/features/pure_virtual_public.cpp] -[pure_virtual_public_impl] +[import ../example/features/optional_result_virtual.cpp] +[optional_result_virtual] The inner `const&` in the postcondition functor parameter type `boost::optional<... const&> ...` is mandatory (the outer `const&` in the postcondition functor parameter type `boost::optional<...> const&` is not). [footnote @@ -52,143 +83,198 @@ In addition, programmers are encouraged to declare the postcondition functor to [endsect] -[section Pure Virtual Public Functions] - -In C++, pure virtual functions are allowed to have a /default implementation/ as long as such implementation is programmed out-of-line so defined outside the class declaring the pure virtual function as `virtual ... = 0;`. -Contracts for pure virtual public functions are programmed using the [funcref boost::contract::public_function] function like for (non-pure) virtual public functions, so all consideration made in __Virtual_Public_Functions__ apply. -However, in this case contracts are always programmed out-of-line, in the default implementation of the pure virtual function. - -For example, note how the following `shape::get_surface` default implementation (which is used to program the pure virtual function contract) must be defined out-of-line and therefore outside the `shape` class declaration (see also [@../../example/features/pure_virtual_public.cpp =pure_virtual_public.cpp=]): - -[pure_virtual_public_base] -[pure_virtual_public_impl] -[pure_virtual_public_derived] - -This library will never actually execute the pure virtual function body while it is calling the pure virtual function default implementation to check its contract for subcontracting. -Therefore, programmers can safely `assert(false)` at the beginning of the body if they intend for that body to never be executed (or they can program a working body in case they need to use C++ pure virtual function default implementation outside of what strictly required by this library). - -Note that because of subcontracting, preconditions of derived class functions are checked in __OR__ with preconditions of base class functions (see __Public_Function_Overrides__). -If base class member functions specify no precondition then preconditions specified by overriding functions in derived classes will have no effect (because when checked in __OR__ with the base class function that has no precondition they will always pass). -This correctly reflects the fact that the base class member function can be called in any context (because it has no precondition) and so must all its overriding function in derived classes in order for the derived class to act like the base class in virtue of inheritance. -However, it is sometimes acceptable for a base class to declare a pure virtual function with a precondition `BOOST_CONTRACT_ASSERT(false)` indicating that the pure virtual function must be redefined by derived classes (as always with pure virtual functions) and also that derived classes will be responsible to specify preconditions (this technique makes sense only for preconditions of pure virtual functions otherwise it will prevent a concrete base function from being ever called successfully). -For example (see also [@../../example/features/named_override.cpp =named_override.cpp=]): - -[import ../example/features/named_override.cpp] -[named_override_pure_virtual_assert_false] - -[endsect] - [section Private and Protected Functions] Private and protected member functions do not check class invariants (because they are not part of the public class interface) and they do not subcontract (because they are not accessible at the calling site where the __substitution_principle__ applies, see also __Function_Calls__). -However, programmers can still choose to specify preconditions and postconditions for private and protected member functions if they want to check correctness of implementations and usage of base member functions in derived classes. -Therefore, when programmers decide to specify contracts for private and protected member functions, they can use [funcref boost::contract::function] (like for non-member functions). +However, programmers may still want to specify preconditions and postconditions for private and protected member functions if they want to check correctness of their implementation and use from within the class, base classes, and friend classes or functions. +When programmers decide to specify contracts for private and protected member functions, they can use [funcref boost::contract::function] (like for non-member functions). For example (see also [@../../example/features/private_protected.cpp =private_protected.cpp=]): [import ../example/features/private_protected.cpp] [private_protected] The same considerations made in __Non_Member_Functions__ apply. -See __Constructors__ and __Destructors__ for notes on how to program contracts for private and protected constructors and destructors respectively. +See __Constructors__ and __Destructors__ for notes on how to program contracts for private and protected constructors and destructors instead. -When private and protected member functions are virtual they should declare the extra parameter of type [classref boost::contract::virtual_]`*` with default value `0` (see __Virtual_Public_Functions__) even if [funcref boost::contract::function] never accepts that as an argument so this parameter will remain unused and it need not a name. -Otherwise, these private and protected virtual functions cannot be overridden by public functions in the derived classes that specifies contracts for the overriding functions (because C++ uses also default parameters to match signatures of overriding functions). -In this case, overriding public functions in derived classes will not specify the extra `override_...` parameter to [funcref boost::contract::public_function] (because the overridden functions are private or protected and not being public they do not participate to subcontracting). +[heading Virtual Private and Protected Functions] + +When private and protected member functions are virtual they should still declare the extra parameter of type [classref boost::contract::virtual_]`*` with default value `0` (see __Virtual_Public_Functions__) even if [funcref boost::contract::function] never accepts that parameter as an argument (so this parameter will remain unused and it does not need a name). +Otherwise, the private and protected virtual functions cannot be overridden by public functions in the derived classes that specify contracts for the overriding functions (because C++ uses also default parameters to match signatures of overriding functions). For example (see also [@../../example/features/private_protected_virtual.cpp =private_protected_virtual.cpp=]): [import ../example/features/private_protected_virtual.cpp] [private_protected_virtual_counter] + +However, public functions in derived classes overriding private or protected virtual functions from base classes will not specify the extra `override_...` template parameter to [funcref boost::contract::public_function] (because the overridden functions are private or protected thus not being public they do not participate to subcontracting), for example (see also [@../../example/features/private_protected_virtual.cpp =private_protected_virtual.cpp=]): + [private_protected_virtual_counter10] -Finally, using multiple inheritance it is also possible to override functions that are private or protected from one base but public from another base. -In this case, overriding public functions in derived classes will specify the extra `override_...` parameter to [funcref boost::contract::public_function] (because the overridden functions private or protected in one base and those do not participate to subcontracting, but public in another base and these participate to subcontracting). +Furthermore, using multiple inheritance it is possible to override functions that are private or protected from one base but public from another base. +In this case, overriding public functions in derived classes will specify the extra `override_...` template parameter to [funcref boost::contract::public_function] (because the overridden functions are private or protected in one base and those do not participate to subcontracting, but public in another base and these participate to subcontracting instead). For example (see also [@../../example/features/private_protected_virtual_multi.cpp =private_protected_virtual_multi.cpp=]): [import ../example/features/private_protected_virtual_multi.cpp] -[private_protected_virtual_multi_counter] [private_protected_virtual_multi_countable] [private_protected_virtual_multi_counter10] [warning Unfortunately, the code above does not compile on MSVC (at least up to Visual Studio 2015) because MSVC incorrectly gives a compile-time error when SFINAE fails due to private or protected access levels. -Instead, GCC and Clang correctly implement SFINAE failures due to private and protected member functions so they successfully compile the code above. +Instead, GCC and Clang correctly implement SFINAE failures due to private and protected member functions so the code above correctly complies on GCC and Clang. ] [endsect] [section Friend Functions] -TODO +Friend functions are not member functions so [funcref boost::contract::function] can used to program contracts for them and all considerations made in __Non_Member_Functions__ apply. +For example (see also [@../../example/features/friend.cpp =friend.cpp=]): + +[import ../example/features/friend.cpp] +[friend_byte] +[friend_bytes] + +However, in some cases a friend function might take an object as parameter and it can be logically considered an extension of the object's public interface (essentially at the same level as the object's public member functions). +In these cases, programmers might chose to program the friend function contracts using [funcref boost::contract::public_function] (instead of [funcref boost::contract::function]) so to also check the class invariants of the object (and not just the pre- and postconditions of the friend function). +For example (see also [@../../example/features/friend_invariant.cpp =friend_invariant.cpp=]): +[footnote +*Rationale:* +Contract programming proposals for C++ like __N1962__ do not provide a mechanism for friend functions to check class invariants of objects passed as parameters. +In other words, these proposals do not allow contracts to recognize that some friend functions logically act as if they were part of the public interface of the objects they take as parameters. +This is reasonable for proposals that add contracts to the core language because friend functions are not always meant to extend an object public interface and C++ does not provide a mechanism to programmatically specify when they do. +However, this library (not being meant to be a revision of the C++ standard itself) has the flexibility to let programmers manually specify when friend functions should also check class invariants of the objects they take as parameters. +] + +[import ../example/features/friend_invariant.cpp] +[friend_invariant] + +This technique can also be extended to friend functions that take multiple objects as parameters and can be logically considered extensions to the public interfaces of each of these objects, for example: + + friend void f(class1& object1, class2* object2, type3& value3) { + // Check just preconditions. + boost::contract::check pre = boost::contract::function() + .precondition([&] { + BOOST_CONTRACT_ASSERT(object2 != nullptr); + ... + }) + ; + // Check class invariants for each object (programmers chose the order). + boost::contract::check inv1 = boost::contract::public_function(&object1); + boost::contract::check inv2 = boost::contract::public_function(object2); + // Check just postconditions. + boost::contract::check post = boost::contract::function() + .postcondition(...) + ; + + ... // Function body. + } + +Changing the order of the [classref boost::contract::check] declarations above, programmers can chose the order for checking class invariants among the different objects passed to the friend function and also whether to check these invariants before or after pre- and postconditions at function entry and exit respectively (see __Non_Member_Functions__ and __Public_Functions__ for information on how the RAII objects returned by [funcref boost::contract::function] and [funcref boost::contract::public_function] check contract conditions). +The example above is programmed to check `class1` invariants before `class2` invariants (but the order could have been inverted if programmers so chose). +Also the example above is programmed to check preconditions before class invariants so the objects passed to the friend function can be validated by the preconditions before they are passed as pointers to [funcref boost::contract::public_function] (e.g., check `object2` is not null). +[footnote +Within member functions instead the object pointer `this` is always well-formed, its validation is never needed, and [funcref boost::contract::public_function] checks class invariants before checking preconditions so programming preconditions can be simplified assuming the class invariants are satisfied already (see __Public_Function_Calls__). +] [endsect] [section Function Overloads] -As seen in __Public_Function_Overrides__, [funcref boost::contract::public_function] takes a pointer to the enclosing function as a parameter when used in overriding public functions. -When an overriding public function is overloaded, the function pointer cannot be automatically deduced by the compiler so programmers have to use `static_cast` to resolve ambiguities (as usual with pointers to overloaded functions in C++). +As seen in __Public_Function_Overrides__, [funcref boost::contract::public_function] takes a pointer to the enclosing function as a parameter when used in public function overrides. +When names of public function overrides are overloaded, the function pointer cannot be automatically deduced by the compiler so programmers have to use `static_cast` to resolve ambiguities (as usual with pointers to overloaded functions in C++). [footnote *Rationale:* -In oder to avoid copies, this library takes all contracted function arguments and the return value as references when passed to [funcref boost::contract::public_function] for overriding public functions. -Therefore, the library cannot differentiate the actual argument and return types of the contracted functions when they are passed by reference and when they are not. -As a result, the library cannot automatically reconstruct the contracted function pointer type which must be instead deduced from the function pointer explicitly passed by programmers to [funcref boost::contract::public_function] (in turn this requires using `static_cast` to resolve ambiguities as usual in C++ when obtaining the pointer of overloaded functions). +In order to avoid copies, this library takes all function arguments and the return value passed to [funcref boost::contract::public_function] as references when used within public function overrides. +Therefore, the library cannot differentiate when the actual function argument and return types are passed by reference and when they are not. +As a result, the library cannot automatically reconstruct the type of the enclosing public function so this type must be deduced from the function pointer explicitly passed by programmers to [funcref boost::contract::public_function]. +When this automatic deduction is not possible due to overloaded function names, programmers must explicitly use `static_cast` to resolve ambiguities as usual in C++ with pointers to overloaded functions. ] For example, note how `static_cast` is used in the following calls to [funcref boost::contract::public_function] (see also [@../../example/features/overload.cpp =overload.cpp=]): [import ../example/features/overload.cpp] [overload] -Overloaded functions have the same function name so the same [^override_['function-name]] type can be used as template parameter of [funcref boost::contract::public_function]. +Overloaded functions have the same function name so the same [^override_['function-name]] type can be used as template parameter for all [funcref boost::contract::public_function] calls. Therefore, [macroref BOOST_CONTRACT_OVERRIDE] only needs to be invoked once for any given function name even when the function name is overloaded (as shown in the example above). [endsect] -[section Named Overrides] +[section Lambdas, Code Blocks, Loops, Etc.] -The function name passed to [macroref BOOST_CONTRACT_OVERRIDE] should never start with an underscore to avoid generating names containing double underscores `override__...` that are reserved by the C++ standard. -There is a separate macro [macroref BOOST_CONTRACT_NAMED_OVERRIDE] that can be used to explicitly specify the name of the type that will be passed to [funcref boost::contract::public_function] as a template argument: -[footnote -*Rationale:* -A different macro [macroref BOOST_CONTRACT_NAMED_OVERRIDE] is used instead of overloading [macroref BOOST_CONTRACT_OVERRIDE] using variadic macros because the override macros cannot be programmed manually by the users so making them variadic would prevent the use of this library on compilers that do not support variadic macros (see also __No_Macros__). -] +So far we have been focused on specifying contracts for function and class interfaces. +While contracts are in general most useful when used to specify interfaces, this library also allows to check contract conditions for implementation code (lambda functions, code blocks, loops, etc.). - BOOST_CONTRACT_OVERRIDE(``[^['function-name]]``) // Generate `override_...`. - BOOST_CONTRACT_NAMED_OVERRIDE(``[^['type-name]]``, ``[^['function-name]]``) // Generate `type-name`. +Lambda functions are not member functions, they are not part of a class public interface so they do not check class invariants or participate int subcontracting, but they can use [funcref boost::contract::function] to specify preconditions, postconditions, and exception guarantees (all considerations made in __Non_Member_Functions__ apply). +For example (see also [@../../example/features/lambda.cpp =lambda.cpp=]): -For example, the following overriding member function is named `_1` so `BOOST_CONTRACT_OVERRIDE(_1)` would generate a type named `override__1` (which is reserved in C++ because it contains double underscores `__`), `BOOST_CONTRACT_NAMED_OVERRIDE(override1, _1)` is used to name the type `override1` instead (see also [@../../example/features/named_override.cpp =named_override.cpp=]): +[import ../example/features/lambda.cpp] +[lambda] -[named_override] +Similarly, [funcref boost::contract::function] can be used to program preconditions, postconditions, and exception guarantees for loops. +For example, for a for-loop but same for while- and all other loops (see also [@../../example/features/loop.cpp =loop.cpp=]): -The [macroref BOOST_CONTRACT_NAMED_OVERRIDE] macro can be used for function names that start with an underscore `_...`, when the name `override_`[^['function-name]] generated by [macroref BOOST_CONTRACT_OVERRIDE] would clash with other names in the user code, to generate names in CamelCase or any other style, in any other case when programmers need or want to generate names different than `override_...`. +[import ../example/features/loop.cpp] +[loop] + +More in general, [funcref boost::contract::function] can be used to program preconditions, postconditions, and exception guarantees of any block of code in a function implementation. +For example (see also [@../../example/features/code_block.cpp =code_block.cpp=]): + +[import ../example/features/code_block.cpp] +[code_block] + +[endsect] + +[section Implementation Checks] + +This library provides a mechanism to check assertions within implementation code outside of preconditions, postconditions, exceptions guarantees, and class invariants. +These implementation checks can be programmed using [macroref BOOST_CONTRACT_ASSERT] in a nullary functor that is directly assigned to [classref boost::contract::check] at the place within the code where the checks have to be executed, for example (see also [@ ../../example/features/check.cpp =check.cpp=]): + +[import ../example/features/check.cpp] +[check_class] + +Alternatively, this library provides the [macroref BOOST_CONTRACT_CHECK] macro that allows to completely remove compile-time and run-time overhead of implementation checks when [macroref BOOST_CONTRAT_NO_CHECKS] is defined (see __Disable_Contract_Checking__ and __Disable_Contract_Compilation__ for similar considerations for all other contract conditions supported by this library), for example (see also [@ ../../example/features/check.cpp =check.cpp=]): + +[check_macro] + +These implementation checks are essentially equivalent to using the C-style `assert` macro but with the following differences: + +* A failure of these implementation checks will call [funcref boost::contract::check_failure] (see also [funcref boost::contract::set_check_failure] and [funcref boost::contract::get_check_failure]). +* These implementation checks are automatically disabled when other contract conditions specified using this libraries are being checked already (to avoid infinite recursion). +* These implementation checks are disabled defining [macroref BOOST_CONTRACT_NO_CHECKS] (instead of `NDEBUG` for disabling `assert`). [endsect] [section Old Values at Body] In the examples seen so far old value variables of type [classref boost::contract::old_ptr] are initialized to a copy of the expression passed to [macroref BOOST_CONTRACT_OLDOF] at the point of their declaration. -This correctly is before the function body is executed but also before the contract is executed, therefore even before class invariants at function entry and preconditions are checked. +This is correctly done before the function body is executed but it is also done before the contract is executed, therefore even before class invariants at function entry and preconditions are checked. -This is convenient and might be sufficient in most cases. -However, in general old values should be copied before executing the function body but after checking entry class invariants and preconditions (see __Assertions__). -There can be cases in which the expression passed to [macroref BOOST_CONTRACT_OLDOF] should be evaluated only if the assertions in class invariants and preconditions are checked to be true. +This might work well in most cases, however in general old values should be copied before executing the function body but after checking entry class invariants and preconditions (see __Assertions__). +There can be cases in which it makes sense to evaluate the expressions passed to [macroref BOOST_CONTRACT_OLDOF] only assuming that the assertions programmed in the class invariants and preconditions are first checked to be true. -This library allows to construct [classref boost::contract::old_ptr] variables using their default constructor (equivalent to a null pointer) and then assign them later to a copy of the expression passed to [macroref BOOST_CONTRACT_OLDOF] in a functor with no parameter [^['h]]`()` passed to `.old(`[^['h]]`)`. -The nullary functor [^['h]]`()` is called by this library before the function body is executed but only after class invariants and preconditions are checked: +For that, this library also allows to construct [classref boost::contract::old_ptr] variables using their default constructor (equivalent to a null pointer) and to assign them later to a copy of the expression passed to [macroref BOOST_CONTRACT_OLDOF] in a nullary functor [^['h]]`()` passed to `.old(`[^['h]]`)`. +The functor [^['h]]`()` is called by this library before the function body is executed but only after class invariants and preconditions are checked: [footnote *Rationale:* -Functors for preconditions, old value assignments, and postconditions are all optional but when specified, they must be specified in this order. -Such order is enforced by the fact that [classref boost::contract::specify_precondition_old_postconditions], [classref boost::contract::specify_old_postcondition], [classref boost::contract::specify_postcondition_only], and [classref boost::contract::specify_nothing] provide a progressively decreasing subset of the `.precondition(...)`, `.old(...)` and `.postcondition(...)` member functions. -The enforced order of preconditions, old value assignments, and postconditions is logical because it reflects the order in which they are executed at run-time. -Other contract programming frameworks allow to mix this order, that could have been implemented for this library too but it would have complicated a somewhat the library implementation while adding no real value (arguably creating confusion because allowing for less logical orderings). +Functors for preconditions, old value assignments, postconditions, and exception guarantees are all optional but when specified, they must be specified in that order. +Such order is enforced by the fact that [classref boost::contract::specify_precondition_old_postcondition_except], [classref boost::contract::specify_old_postcondition_except], [classref boost::contract::specify_postcondition_except], [classref boost::contract::specify_except], and [classref boost::contract::specify_nothing] provide a progressively decreasing subset of the `.precondition(...)`, `.old(...)`, `.postcondition(...)`, and `.except(...)` member functions. +The enforced order for specifying preconditions, old value assignments, postconditions, and exception guarantees makes logical sense because it follows the order at which these are executed at run-time. +Other contract programming frameworks allow to mix this order, that could have been implemented for this library as well but it would have complicated somewhat the library implementation while adding no real value (arguably creating confusion in user code by not enforcing a consistent order for specifying contract conditions). ] - boost::contract::old_ptr<...> old_``[^['name]]``; // Use default constructor. + boost::contract::old_ptr<...> old_``[^['name]]``; // Default constructor (i.e., null pointer). + ... boost::contract::guard c = boost::contract::function() // Same for all other contracts. ... .old([&] { // Capture by reference... old_``[^['name]]`` = BOOST_CONTRACT_OLDOF(``[^['expression]]``); // ...but modify only old values. + ... }) .postcondition([&] { - BOOST_CONTRACT_ASSERT(*old_``[^['name]]`` ...); + BOOST_CONTRACT_ASSERT(*old_``[^['name]]`` ...); // Never null here. + ... + }) + .except([&] { + BOOST_CONTRACT_ASSERT(*old_``[^['name]]`` ...); // Never null here. ... }) ; @@ -200,131 +286,53 @@ Therefore, `old_y` is first declared using its default constructor (i.e., initia [old] The functor passed to `.old(...)` should capture all variables it needs to evaluate and copy old value expressions. -In general, these variables should be captured by reference and not by value (because old values need to copy values the variables will have just before executing the function body, and not the value these variables had when the functor passed to `.old(...)` was first declared). -In any case, this functor should modify only old values and not the value of other captured variables (see also __Constant_Correctness__). +In general, these variables should be captured by reference and not by value (because old values need to make copies of the values the captured variables will have just before executing the function body, and not copy the values these variables had when the functor passed to `.old(...)` was first declared). +In any case, the functor passed to `.old(...)` should modify only old values and not the values of other captured variables (see also __Constant_Correctness__). -This library will automatically call [funcref boost::contract::postcondition_failure] if calling the functor specified via `.old(...)` throws an exception (by default, this terminates the program calling `std::terminate`, but see __Throw_on_Failure__ to throw exceptions, exit the program with an error code, etc.). +This library will automatically call the failure handler [funcref boost::contract::old_failure] if calling the functor specified via `.old(...)` throws an exception (by default, this handler prints an error message to `std::cerr` and terminates the program calling `std::terminate`, but see __Throw_on_Failure__ to throw exceptions, exit the program with an error code, etc.). + +[note +If old value pointers are initialized at the point of their construction instead of using `.old(...)` then an exception thrown by the old value expression [macroref BOOST_CONTRACT_OLDOF], or more in general any exception thrown by the old value pointer initialization, will result in that exception being thrown up the stack by the enclosing user-defined function. +This is arguably less correct than calling [funcref boost::contract::old_failure] because an exception thrown by an old value copy causes the program to fail checking its postconditions and exception guarantees but should not automatically causes the enclosing user-defined function to thrown an exception (this might not be a significant difference in practice, or it could be an additional reason to use `.old(...)` instead of copying old values when they are declared before the contract). [footnote *Rationale:* -If old value pointers are assigned at the point of their construction instead of using `.old(...)` then an exception thrown by the old value expression [macroref BOOST_CONTRACT_OLDOF] or more in general any exception thrown by the old value pointer initialization will result in that exception being thrown up the stack by the contracted function. -This is arguably less correct than calling [funcref boost::contract::postcondition_failure] because an exception thrown by an old value copy causes the program to fail checking its postconditions and should not technically causes the contracted function to thrown an exception (however, this might not be a significant difference in practice). -Note that while it would be possible to wrap all old value operations ([refclass boost::contract::old_ptr] copy constructor, [funcref boost::contract::make_old], etc.) in try-catch statements so this library will call [funcref boost::contract::postcondition_failure] also when old values are copied when they are constructed outside `.old(...)`, that will prevent this library from knowing the [enumref boost::contract::from] parameter which is not acceptable (specifically because destructors can have postconditions). +It would be possible to wrap all old value operations ([classref boost::contract::old_ptr] copy constructor, [funcref boost::contract::make_old], etc.) in try-catch statements so this library will call [funcref boost::contract::postcondition_failure] also when old values are copied when they are constructed outside `.old(...)`. +However, that will prevent this library from knowing the [enumref boost::contract::from] parameter which will not be viable (specifically because destructors can have postconditions so that parameter is necessary to make sure user-defined failure handlers can be programmed to never throw from destructors as C++ requires). +] ] [endsect] -[section Old Value Requirements] +[section Named Overrides] -Old values require copying the expression passed to [macroref BOOST_CONTRACT_OLDOF] so the type of that expression must be copy constructible. -More precisely, dereferencing an old value pointer of type [classref boost::contract::old_ptr]`` requires `boost::is_copy_constructible::value` to be `true` (otherwise this library will generate a compile-time error). - -* In some cases it might be acceptable, or even desirable, to cause a compile-time error when a program uses old value types that are not copy constructible (because it is not possible to fully check the correctness of the program as stated by the contract assertions that use these old values). -In these cases, programmers can declare old values using [classref boost::contract::old_ptr] as seen so far (or equivalently using C++11 `auto` declarations `auto ... = BOOST_CONTRACT_OLDOF(...)`). +The function names passed to [macroref BOOST_CONTRACT_OVERRIDE] and [macroref BOOST_CONTRACT_OVERRIDES] should never start with an underscore to avoid generating names containing double underscores `override__...` (which are reserved by the C++ standard). +There is a separate macro [macroref BOOST_CONTRACT_NAMED_OVERRIDE] that can be used to explicitly specify the name of the type that will be passed to [funcref boost::contract::public_function] as a template argument: [footnote *Rationale:* -When C++11 `auto` declarations are used, this library defaults the type of [macroref BOOST_CONTRACT_OLDOF] to [classref boost::contract::old_ptr] because it generates a compile-time error for non-copyable types so it is in general more conservative than [classref boost::contract::old_ptr_noncopyable]. +A different macro [macroref BOOST_CONTRACT_NAMED_OVERRIDE] is used instead of overloading [macroref BOOST_CONTRACT_OVERRIDE] using variadic macros because the override macros cannot be programmed manually by the users so making them variadic would prevent to use this library on compilers that do not support variadic macros (see also __No_Macros__). ] -* However, in other cases it might be desirable to simply not check assertions that use some old values when the related old value types are not copy constructible. -Programmers can do this by using [classref boost::contract::old_ptr_noncopyable] instead of [classref boost::contract::old_ptr] to program these old values (and by checking if the old value pointer is not null before dereferencing it in postconditions). -For example, consider the following `accumulate` function template that could in general be instantiated for types `T` that are not copy constructible, that is when `boost::is_copy_constructible::value` is `false` (see also [@../../example/features/old_noncopyable.cpp =noncopyable.cpp=]): + BOOST_CONTRACT_OVERRIDE(``[^['function-name]]``) // Generate `override_...`. + BOOST_CONTRACT_NAMED_OVERRIDE(``[^['type-name]]``, ``[^['function-name]]``) // Generate `type-name`. -[/ import ../example/features/old_noncopyable.cpp] -[old_noncopyable] +For example, the following public function override is named `_1` so `BOOST_CONTRACT_OVERRIDE(_1)` would generate a type named `override__1` (which is reserved in C++ because it contains double underscores `__`), `BOOST_CONTRACT_NAMED_OVERRIDE(override1, _1)` is used to name the type `override1` instead (see also [@../../example/features/named_override.cpp =named_override.cpp=]): -The old value pointer `old_total` is programmed using [classref boost::contract::old_ptr_noncopyable] so if `T` is not copy constructible then `total` will simply not be copied and `old_total` will be left as a null pointer (in these cases `old_total` must be checked to be not null `if(old_total) ...` before it can be dereferenced in the postconditions). -If the above example used [classref boost::contract::old_ptr] instead then the library would have generated a compile-time error if `accumulate` is instantiated for types `T` that are not copy constructible (but only if `old_total` is actually dereferenced in the contract assertions somewhere `*old_total ...`). +[named_override] -The `..._noncopyable` postfix in the type name [classref boost::contract::old_ptr_noncopyable]`` refers to the pointed type `T` that may or not be copy constructible without causing a compile-time error in this case (the old value pointer itself is always copyable, or at least copy assignable). +The [macroref BOOST_CONTRACT_NAMED_OVERRIDE] macro can also be used when the name `override_`[^['function-name]] generated by [macroref BOOST_CONTRACT_OVERRIDE] would clash with other names in user code, to generate names in CamelCase or in any other style, in any other case when programmers need or want to generate names different from `override_...`. -[heading No C++11] - -In general, the `boost::is_copy_constructible` type trait requires C++11 for full support. -On non-C++11 compilers, it is possible to inherit the old value type from `boost::noncopyable`, or use `BOOST_MOVABLE_BUT_NOT_COPYABLE`, or explicitly specialize the `boost::is_copy_constructible` template (see [@http://www.boost.org/doc/libs/release/libs/type_traits/doc/html/boost_typetraits/reference/is_copy_constructible.html boost::is_copy_constrictible] for more information): - - #include - - namespace boost { - template<> - struct is_copy_constructible<``[^['old-value-type]]``> : false_type {}; - } - -[endsect] - -[section Assertion Requirements (Static-If)] - -In general, assertions can introduce a new set of requirements on the types used by the program. -Some of these type requirements might be necessary only to check the assertions and they would not be required by the program otherwise. - -* In some cases it might be acceptable, or even desirable, to cause a compile-time error when a program uses types that do not provide all the operations needed to check contract assertions (because it is not possible to fully check the correctness of the program as stated by the contracts). -In these cases, programmers can specify contract assertions as we have seen so far, compilation will fail if user types do not provide all operations necessary to check the contracts. -* However, in other cases it might be desirable that adding contracts to a program does not alter its type requirements and that assertions are simply not checked when user types do not provide all the operations necessary to check them. -Programmers can do this by using [funcref boost::contract::check_if] (and [funcref boost::contract::check_if_c]) within the contract assertions. - -For example, let's consider the following `vector` class template. -This class template does not usually require that `T` has an equality operator `==` (it only requires `T` to be copy constructible, see `std::vector` documentation). -However, the contracts of the `vector::push_back(value)` member function include a postcondition `back() == value` which introduces the new requirement that `T` must also have an equality operator `==`. -Programmers can specify this postcondition as usual `BOOST_CONTRACT_ASSERT(back() == value)` an let the program fail to compile when users instantiate this template with a type `T` that does not provide an equality operator `==`. -Otherwise, programmers can specify this postcondition using [funcref boost::contract::check_if] to check the assertion only for types `T` that have an equality operator `==` and trivially check `true` otherwise, for example (see also [@../../example/features/condition_if.cpp =condition_if.cpp=]): - -[import ../example/features/condition_if.cpp] -[condition_if] - -The [funcref boost::contract::check_if] function template is a special case of the more general facility [funcref boost::contract::call_if]: -Specifically, `boost::contract::check_if<`[^['condition]]`>(`[^['check]]`)` is equivalent to: - - boost::contract::call_if<``[^['condition]]``>( - ``[^['check]]`` - ).else_( - [] { return true; } - ) - -Where [^['condition]] is a nullary boolean meta-function and [^['check]] is a nullary boolean functor. -If [^['condition]]`::value` is statically evaluated to be `true` at compile-time then [^['check]]`()` is called at run-time and its boolean result is returned by the enclosing `call_if`. -Otherwise, if [^['condition]]`::value` is statically evaluated to be `false` at compile-time then `[] { return true; }()` is called at run-time and `true` is trivially returned by the enclosing `call_if`. -Note that [^['check]] must be a functor template (and not just a functor) so its code that contains the assertion operations with the extra type requirements (e.g., the operator `==`) will not be instantiated and compiled for specific types unless the compiler determines it will be actually called at run-time (C++14 generic lambdas and functor templates like `std::equal_to` can be used to program [^['check]], but C++11 lambdas cannot). - -More in general, [funcref boost::contract::call_if] accepts a number of optional else-if and one optional else statement: - - boost::contract::call_if<``[^['condition1]]``>( - ``[^['then1]]`` - ).template else_if<``[^['condition2]]``>( // Optional. - ``[^['then2]]`` - ) - ... // Optionally, other `else_if`. - .else_( // Optional for `void` functors, otherwise required. - ``[^['else]]`` - ) - -Where [^['condition1]], [^['condition2]], ... are nullary boolean meta-functions and [^['then1]], [^['then2]], ..., [^['else]] are nullary functors. -The return types of the functor calls [^['then1]]`()`, [^['then2]]`()`, ..., [^['esle]]`()` must either all be the same (possibly all `void`) or be of types implicitly convertible into one another. -At run-time [funcref boost::contract::call_if] will call the functor [^['then1]]`()`, or [^['then2]]`()`, ..., or [^['else]]`()` depending on which meta-function [^['condition1]]`::value`, [^['condition2]]`::value`, ... is evaluated to be `true` or `false` at compile-time, at it will return the value returned by the functor being called -If [^['then1]], [^['then2]], ..., [^['else]] are nullary functor templates (not just nullary functors) then their code will only be compiled if the compiler determines they need to be actually called at run-time (so only if the related [^['condition1]]`::value`, [^['condition2]]`::value`, ... are evaluated to be `true` or `false` at compile-time). -All the `esle_if<...>(...)` statements are optional, the `else_(...)` statement is optional if the functor calls return `void` but it is required otherwise. - -In general, [funcref boost::contract::call_if] can be used to program contract assertions that compile and check different functor templates depending on related conditions being evaluated to be `true` at compile-time (but in most cases [funcref boost::contract::check_if] should be sufficient, simpler and less verbose to use). - -The [funcref boost::contract::check_if_c], [funcref boost::contract::call_if_c], and `.else_if_c` function templates work similarly to their counterparts without the `..._c` postfix above, but they take their condition template parameters as static boolean values instead of nullary boolean meta-functions. - -[heading Static-If (C++14)] - -The [funcref boost::contract::call_if] function template is a general facility and its use is not limited to programming contracts. -In fact, [funcref boost::contract::call_if] can be used together with C++14 generic lambdas to program statements similar to the `static if` proposal (at least at function scope, see also [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3613.pdf N3613]). -For example, consider the following implementation of `std::advance` that uses `static if`-like statements programmed via [funcref boost::contract::call_if] (see also [@../../example/features/call_if_cxx14.cpp =call_if_cxx14.cpp=]): - -[import ../example/features/call_if_cxx14.cpp] -[call_if_cxx14] - -This implementation is much more concise, easy to read and maintain than the usual implementation of `std::advance` that uses tag dispatching. +Note that there is not a `BOOST_CONTRACT_NAMED_OVERRIDES` macro so [macroref BOOST_CONTRACT_NAMED_OVERRIDE] needs to be invoked separately on each function name (there is instead a [macroref BOOST_CONTRACT_OVERRIDES] macro as seen in __Public_Function_Overrides__). [footnote -`boost::hana::if_` can also be used to emulate function scope `static if` with C++14 generic lambdas. +*Rationale:* +The syntax for invoking a possible `BOOST_CONTRACT_NAMED_OVERRIDES` macro would need to be something like `BOOST_CONTRACT_NAMED_OVERRIDES((`[^['type-name1]]`, `[^['function-name1]]`), (`[^['type-name2]]`, `[^['function-name2]]`), ...)`. +The authors felt this syntax is more cumbersome than repeating single `BOOST_CONTRACT_NAMED_OVERRIDE` invocations `BOOST_CONTRACT_NAMED_OVERRIDE(`[^['type-name1]]`, `[^['function-name1]]`) BOOST_CONTRACT_NAMED_OVERRIDE(`[^['type-name2]]`, `[^['function-name2]]`) ...` so decided not to provide the `BOOST_CONTRACT_NAMED_OVERRIDES` macro. ] [endsect] [section Access Specifiers] -As seen so far, programmers are required to decorate their classes declaring extra members that are internally used by this library to check contracts: +As we have seen so far, programmers are required to decorate their classes declaring extra members that are internally used by this library to check contracts: * The `invariant` and `static_invariant` member functions (used to check class invariants, see also __Class_Invariants__). * The `base_types` member type declared via [macroref BOOST_CONTRACT_BASE_TYPES] (used to implement subcontracting, see also __Public_Function_Overrides__). @@ -344,7 +352,7 @@ the `override_...` member types do not have to be declared `public` on any compi In any case, declaring the [classref boost::contract::access] class `friend` allows to always declare all these extra members `private` on all compilers. ] However, programmers might need to more precisely control the public members of their classes to prevent incorrect access of encapsulated members. -All these members can be declared `private` as long as the [classref boost::contract::access] class is declared as `friend`, for example (see also [@../../example/features/access.cpp =access.cpp=]): +All these members can be declared `private` as long as the [classref boost::contract::access] class is declared as `friend` of the user class, for example (see also [@../../example/features/access.cpp =access.cpp=]): [import ../example/features/access.cpp] [access] @@ -355,46 +363,61 @@ This technique is not used in most examples of this documentation only for brevi [section Throw on Failure] -If a condition checked using [macroref BOOST_CONTRACT_ASSERT] is `false` or if code specified in preconditions, postconditions, and class invariants throws an exception, this library calls the /contract failure handler/ functions [funcref boost::contract::precondition_failure], [funcref boost::contract::postcondition_failure], [funcref boost::contract::entry_invariant_failure], or [funcref boost::contract::exit_invariant_failure] respectively (in fact, [macroref BOOST_CONTRACT_ASSERT] simply expands to code that throws a [classref boost::contract::assertion_failure] exception, see also __No_Macros__). +If a conditions checked using [macroref BOOST_CONTRACT_ASSERT] is evaluated to be `false` or more in general if any of the specified contract code throws an exception (in fact, [macroref BOOST_CONTRACT_ASSERT] simply expands to code that throws a [classref boost::contract::assertion_failure] exception, see also __No_Macros__), this library will call an appropriate /contract failure handler/ function as follow: -By default, the contract failure handler functions print a message to the standard error `std::cerr` and then terminate the program calling `std::terminate`. +# False [macroref BOOST_CONTRACT_ASSERT] assertions and exceptions thrown from preconditions `.precondition(...)` call [funcref boost::contract::precondition_failure]. +# False [macroref BOOST_CONTRACT_ASSERT] assertions and exceptions thrown from postconditions `.postcondition(...)` call [funcref boost::contract::postcondition_failure]. +# False [macroref BOOST_CONTRACT_ASSERT] assertions and exceptions thrown from exception guarantees `.except(...)` call [funcref boost::contract::except_failure]. +# False [macroref BOOST_CONTRACT_ASSERT] assertions and exceptions thrown from class invariants `invariant()` and `static_invariant()` call [funcref boost::contract::entry_invariant_failure] when checked at function entry and [funcref boost::contract::exit_invariant_failure] when checked at function exit. +# Exceptions thrown from old value copies at body `.old(...)` call [funcref boost::contract::old_failure]. +# False [macroref BOOST_CONTRACT_ASSERT] assertions and exceptions thrown from implementation checks `boost::contract::check c = `[^['nullary-functor]] and [macroref BOOST_CONTRACT_CHECK] call [funcref boost::contract::check_failure]. + +By default, these contract failure handlers print a message to the standard error `std::cerr` and then terminate the program calling `std::terminate`. [footnote *Rationale:* -In general, when a contract fails the only safe thing to do is to terminate the program execution (because the contract failure indicates a bug in the program, and in general the program is in a state for which no operation can be successfully performed, so the program should be stopped). +In general, when a contract fails the only safe thing to do is to terminate program execution (because the contract failure indicates a bug in the program, and in general the program is in a state for which no operation can be successfully performed, so the program should be stopped). Therefore, this library terminates the program by default. However, for specific applications, programmers could implement some fail-safe mechanism for which some mission-critical operation can always be performed upon handling failures so this library allows programmers to override the default contract failure handlers to fully customize how to handle contract failures. ] -However, programmers can override the default contract failure handlers to perform any custom action on contract failure using [funcref boost::contract::set_precondition_failure], [funcref boost::contract::set_postcondition_failure], [funcref boost::contract::set_entry_invariant_failure], [funcref boost::contract::set_exit_invariant_failure], [funcref boost::contract::set_invariant_failure] (to set both entry and exit invariant failure handlers at once for convenience), or [funcref boost::contract::set_failure] (to set all failure handlers at once for convenience). +However, programmers can override the default contract failure handlers to perform any custom action on contract failure using the following functions respectively: + +# [funcref boost::contract::set_precondition_failure] +# [funcref boost::contract::set_postcondition_failure] +# [funcref boost::contract::set_except_failure] +# [funcref boost::contract::set_entry_invariant_failure] and [funcref boost::contract::set_exit_invariant_failure], or [funcref boost::contract::set_invariant_failure] (to set both entry and exit invariant failure handlers at once for convenience) +# [funcref boost::contract::set_old_failure] +# [funcref boost::contract::set_check_failure] + +These `set_..._failure(`[^['f]]`)` function calls return the contract failure handler functor [^['f]] that they take as input parameter so these calls can be concatenated. For example (see also [@../../example/features/throw_on_failure.cpp =throw_on_failure.cpp=]): [import ../example/features/throw_on_failure.cpp] [throw_on_failure_handler] -Note that in order to comply with C++ and STL exception safety rules, destructors should never throw. -This library passes a [classref boost::contract::from] parameter to the contract failure handler functions that indicates if the contract failure occurred in a destructor, constructor, or function call. -This way programmers can ensure to never throw from a destructor call (in the example above, contract failures from destructors are simply ignored even if that is probably never a safe thing to do in real code). -[footnote -It is the responsibility of the programmers to decide how to handle contract failures from destructors when they reprogram the contract failure handlers to throw exceptions instead of terminating the program (given that C++ and STL exception safety rules requires destructors to never throw). -This is not a simple dilemma and it might be one more reason to terminate the program instead of throwing exceptions when contract assertions fail (as this library does by default). +When programming custom failure handlers that trow exceptions instead of terminating the program, programmers should be wary of the following: + +* In order to comply with C++ and STL exception safety, destructors should never throw. +This library passes a [classref boost::contract::from] parameter to the contract failure handlers for preconditions ([funcref boost::contract::precondition_failure]), postconditions ([funcref boost::contract::postcondition_failure]), class invariants ([funcref boost::contract::entry_invariant_failure] and [funcref boost::contract::exit_invariant_failure]), and old value copies at body ([funcref boost::contract::old_failure]). +This [classref boost::contract::from] parameter indicates if the contract failure occurred in a destructor, constructor, or function call so programmers can use it code custom contract failure hander functions that never throw from destructors (in the example above, contract failures from destructors are simply ignored even if that is probably never a safe thing to do in real code). +* Implementation checks can appear in any code, including destructor implementation code, so [funcref boost::contract::check_failure] should also never throw, or implementation checks should never be used in destructors. +* The contract failure handler for exception guarantees [funcref boost::contract::except_failure] should also never throw (regardless of its [classref boost::contract::from] parameter). +That is because when [funcref boost::contract::except_failure] is called there is already an active exception on the stack, the exception that triggered the exception guarantees to be checked in the first place (throwing an exception while there is already an active exception leads to undefined behaviour in C++, most programs will segfault). + +[note +It is the responsibility of the programmers to decide how to handle contract failures from destructors when they program custom contract failure handlers that throw exceptions instead of terminating the program (given that C++ and STL exception safety rules requires destructors to never throw). +This is not a simple dilemma and it might be one more reason to terminate the program instead of throwing exceptions when assertions fail in C++ (as this library and also the C-style `assert` do by default). ] -The contract assertions can be programmed to throw [classref boost::contract::assertion_failure] using [macroref BOOST_CONTRACT_ASSERT] (see also __No_Macros__) or to throw any other exception using code similar to: +Contract assertions can be programmed to throw [classref boost::contract::assertion_failure] using [macroref BOOST_CONTRACT_ASSERT]`(`[^['condition]]`)` as we have seen so far (see also __No_Macros__). +Alternatively, contract assertions can be programmed to throw any other exception (including user-defined exceptions) using code similar to the following: - if(``[^['error-condition]]``) throw ``[^['exception-object]]``; + if(!``[^['condition]]``) throw ``[^['exception-object]]``; For example (see also [@../../example/features/throw_on_failure.cpp =throw_on_failure.cpp=]): [throw_on_failure_cstring] -[endsect] - -[section Disable Contract Checking] - -Checking contracts adds run-time overhead and can slow down program execution (see also __Benefits_and_Costs__). -Therefore, programmers can define the following macros (`-D` option in Clang and GCC, `/D` option in MSVC, etc.) to instruct this library to not check specific set of contracts at run-time: [macroref BOOST_CONTRACT_NO_PRECONDITIONS] (do not check preconditions), [macroref BOOST_CONTRACT_NO_POSTCONDITIONS] (do not check postconditions), [macroref BOOST_CONTRACT_NO_ENTRY_INVARIANTS] (do not check invariants at call entry), [macroref BOOST_CONTRACT_NO_EXIT_INVARIANTS] (do not check invariants at call exit), and [macroref BOOST_CONTRACT_NO_INVARIANTS] (do not check invariants at both call entry and exit). -By default, none of these macros are defined so this library checks all contracts. - -For example, programmers could decide to check all contracts during early development builds, but later check only preconditions and maybe entry invariants for release builds by defining [macroref BOOST_CONTRACT_NO_POSTCONDITIONS] and [macroref BOOST_CONTRACT_NO_EXIT_INVARIANTS]. +In the example above, [funcref boost::contract::precondition_failure] will be called if the precondition functor throws the user-defined exception `too_large_error` (exactly the same as when a precondition programmed using [macroref BOOST_CONTRACT_ASSERT] fails). [endsect] diff --git a/doc/bibliography.qbk b/doc/bibliography.qbk index 415fe88..4c07747 100644 --- a/doc/bibliography.qbk +++ b/doc/bibliography.qbk @@ -60,6 +60,8 @@ This section lists all references consulted while designing and developing this [#N2906_anchor] [N2906] B. Stroustrup. [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2009/n2906.pdf /Simplifying the sue of concepts/]. The C++ Standards Committee, N2906, 2009. +[#N3613_anchor] [N3613] B. Stroustrup, G. Dos Reis, A. Sutton. [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3613.pdf /"Static If" Considered/]. The C++ Standards Committee, N3613, 2013. + [#Rosenblum95_anchor] [Rosenblum95] D. S. Rosenblum. [@http://www.cs.toronto.edu/~chechik/courses06/csc410/rosenblum_assert95.pdf /A practical Approach to Programming With Assertions/]. IEEE Transactions on Software Engineering, 1995. [#SPARKAda_anchor] [SPARKAda] Praxis. [@http://www.praxis-his.com/sparkada/language.asp /SPARKAda (Ada-like Language with Contract Programming)/]. diff --git a/doc/contract_programming_overview.qbk b/doc/contract_programming_overview.qbk index 576305a..3b00aad 100644 --- a/doc/contract_programming_overview.qbk +++ b/doc/contract_programming_overview.qbk @@ -341,7 +341,7 @@ This library contract failure handlers report information about the failure that [endsect] -[section Features] +[section Feature Summary] The Contract Programming features supported by this library are largely based on __N1962__ and on the Eiffel programming language. The following table compares Contract Programming features among this library, the __N1962__ proposal (unfortunately the C++ standard committee rejected this proposal commenting on a general lack of need for adding Contract Programming to C++ at the time, even if __N1962__ itself is sound), a more recent proposal __P0186__ (which unfortunately only supports preconditions and postconditions, but does not support class invariants, subcontracting, and not even old values for postconditions), the Eiffel and D programming languages: diff --git a/doc/extra_topics.qbk b/doc/extra_topics.qbk new file mode 100644 index 0000000..a58fcc2 --- /dev/null +++ b/doc/extra_topics.qbk @@ -0,0 +1,446 @@ + +[/ Copyright (C) 2008-2016 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] + +[section Extra Topics] + +This section can be consulted selectively for specific topics of interest. + +[section Old Value Requirements (Templates)] + +Old values require to copy the expression passed to [macroref BOOST_CONTRACT_OLDOF] thus the type of that expression must be copy constructible. +More precisely, dereferencing an old value pointer of type [classref boost::contract::old_ptr]`` requires `boost::is_copy_constructible::value` to be `true` (otherwise this library will generate a compile-time error). + +In some cases it might be acceptable, or even desirable, to cause a compile-time error when a program uses old value types that are not copy constructible (because it is not possible to fully check the correctness of the program as stated by the contract assertions that use the old values). +In these cases, programmers can declare old values using [classref boost::contract::old_ptr] as seen so far. + +However, in other cases it might be desirable to simply not check assertions that use old values when the respective old value types are not copy constructible. +Programmers can do this by using [classref boost::contract::old_ptr_if_copyable] instead of [classref boost::contract::old_ptr] to program these old values (and by checking if the old value pointer is not null before dereferencing it in postconditions). +For example, consider the following function template that could in general be instantiated for types `T` that are not copy constructible (that is for which `boost::is_copy_constructible::value` is `false`, see also [@../../example/features/old_if_copyable.cpp =old_if_copyable.cpp=]): +[footnote +*Rationale:* +__N1962__ and other proposals to add contracts to C++ do not provide a mechanism to selectively disable copies for only old value types that are not copy constructible. +However, this library provides such a mechanism to allow to program contracts for template code without necessarily adding extra copy constructible type requirements that would not be present if it were not for copying the old values (so compiling the code with and without contracts will not necessarily alter the type requirements of the program). +As for extending the C++ language, something similar could be achieved by combing both __N1962__ (contracts) and __N3613__ (`static if`) so that old value expressions within template code could be guarded by `static if` statements checking if the old value types are copyable or not. +] + +[import ../example/features/old_if_copyable.cpp] +[old_if_copyable] + +The old value pointer `old_total` is programmed using [classref boost::contract::old_ptr_if_copyable] so if `T` is not copy constructible then `total` will simply not be copied and `old_total` will be left as a null pointer (in these cases `old_total` must be checked to be not null `if(old_total) ...` before it can be dereferenced in postconditions and exception guarantees). +If the above example used [classref boost::contract::old_ptr] instead then the library would have generated a compile-time error when `accumulate` is instantiated with types `T` that are not copy constructible (but only if `old_total` is actually dereferenced somewhere in the contract assertions using `*old_total ...`, `old_total->...`, etc.). + +[note +The `..._if_copyable` postfix in the type name [classref boost::contract::old_ptr_if_copyable]`` refers to the pointed type `T` which might or not be copy constructible without causing a compile-time error in this case (the old value pointer itself is always copyable, or at least copy-assignable). +] + +When C++11 `auto` declarations are used with [macroref BOOST_CONTRACT_OLDOF], this library always defaults to using the [classref boost::contract::old_ptr] type (because this type requirements are more stringent than the requirements of [classref boost::contract::old_ptr_if_copyable]). +For example, the following will use [classref boost::contract::old_ptr] and not [classref boost::contract::old_ptr_if_copyable] to declare `old_x`: + + auto old_x = BOOST_CONTRACT_OLDOF(x); // C++11 auto declarations. + +[heading No C++11] + +In general, the `boost::is_copy_constructible` type trait requires C++11 for full support. +On non-C++11 compilers, it is possible to inherit the old value type from `boost::noncopyable`, or use `BOOST_MOVABLE_BUT_NOT_COPYABLE`, or explicitly specialize the `boost::is_copy_constructible` template (see [@http://www.boost.org/doc/libs/release/libs/type_traits/doc/html/boost_typetraits/reference/is_copy_constructible.html boost::is_copy_constrictible] for more information). +For example, for some non-copyable old value type `n` (see also [@../../example/features/old_if_copyable.cpp =old_if_copyable.cpp=]): + +[old_if_copyable_specialization] + +[endsect] + +[section Assertion Requirements (Templates)] + +In general, assertions can introduce a new set of requirements on the types used by the program. +Some of these type requirements might be necessary only to check the assertions and they would not be required by the program otherwise. + +In some cases it might be acceptable, or even desirable, to cause a compile-time error when a program uses types that do not provide all the operations needed to check contract assertions (because it is not possible to fully check the correctness of the program as stated by the contracts). +In these cases, programmers can specify contract assertions as we have seen so far, compilation will fail if user types do not provide all operations necessary to check the contracts. + +However, in other cases it might be desirable that adding contracts to a program does not alter its type requirements and that assertions are simply not checked when user types do not provide all the operations necessary to check the assertions. +Programmers can do this by using [funcref boost::contract::condition_if] (or [funcref boost::contract::condition_if_c]) within the contract assertions. + +For example, let's consider the following `vector` class template. +This class template does not usually require that its type parameter `T` has an equality operator `==` (it only requires `T` to be copy constructible, see `std::vector` documentation). +However, the contracts of the `vector::push_back(value)` member function include a postcondition `back() == value` which introduces the new requirement that `T` must also have an equality operator `==`. +Programmers can specify this postcondition as usual with `BOOST_CONTRACT_ASSERT(back() == value)` an let the program fail to compile when users instantiate `vector` with a type `T` that does not provide an equality operator `==`. +Otherwise, programmers can specify this postcondition using [funcref boost::contract::condition_if] to evaluate the asserted condition only for types `T` that have an equality operator `==` and trivially evaluate to `true` otherwise, for example (see also [@../../example/features/condition_if.cpp =condition_if.cpp=]): + +[import ../example/features/condition_if.cpp] +[condition_if] + +The [funcref boost::contract::condition_if] function template is a special case of the more general facility [funcref boost::contract::call_if]: +Specifically, `boost::contract::condition_if<`[^['Predicate]]`>(`[^['condition]]`)` is equivalent to: + + boost::contract::call_if<``[^['Predicate]]``>( + ``[^['condition]]`` + ).else_( + [] { return true; } + ) + +Where [^['Predicate]] is a nullary boolean meta-function and [^['condition]] is a nullary boolean functor. +If [^['Predicate]]`::value` is statically evaluated to be `true` at compile-time then [^['condition]]`()` is called at run-time and its boolean result is returned by the enclosing `call_if`. +Otherwise, if [^['Predicate]]`::value` is statically evaluated to be `false` at compile-time then the lambda function `[] { return true; }()` is called at run-time and `true` is trivially returned by the enclosing `call_if`. +Note that [^['condition]] must be a functor template (and not just a functor) so its code that contains the assertion operations with the extra type requirements (e.g., the equality operator `==`) will not be instantiated and compiled for specific types unless the compiler determines that [^['condition]]`()` needs to be actually called at run-time (functor templates like `std::equal_to` and C++14 generic lambdas can be used to program [^['condition]], but C++11 lambdas cannot). + +More in general, [funcref boost::contract::call_if] accepts a number of optional /else-if/ statements and one optional /else/ statement: + + boost::contract::call_if<``[^['Predicate1]]``>( + ``[^['then1]]`` + ).template else_if<``[^['Predicate2]]``>( // Optional. + ``[^['then2]]`` + ) + ... // Optionally, other `else_if` statements. + .else_( // Optional for `void` functors, otherwise required. + ``[^['else]]`` + ) + +Where [^['Predicate1]], [^['Predicate2]], ... are nullary boolean meta-functions and [^['then1]], [^['then2]], ..., [^['else]] are nullary functors. +The return types of the functor calls [^['then1]]`()`, [^['then2]]`()`, ..., [^['else]]`()` must either be all the same (including all `void`) or be of types implicitly convertible into one another. +At run-time [funcref boost::contract::call_if] will call the functor [^['then1]]`()`, or [^['then2]]`()`, ..., or [^['else]]`()` depending on which meta-function [^['Predicate1]]`::value`, [^['Predicate2]]`::value`, ... is statically evaluated to be `true` or `false` at compile-time, and it will return the value returned by the functor being called. +If [^['then1]], [^['then2]], ..., [^['else]] are nullary functor templates (not just nullary functors) then their code will only be compiled if the compiler determines they need to be actually called at run-time (so only if the related [^['Predicate1]]`::value`, [^['Predicate2]]`::value`, ... are evaluated to be `true` or `false` at compile-time). +All the `else_if<...>(...)` statements are optional, the `else_(...)` statement is optional if the functor calls return `void` but it is required otherwise. + +In general, [funcref boost::contract::call_if] can be used to program contract assertions that compile and check different functor templates depending on related conditions being statically evaluated to be `true` or `false` at compile-time (but in most cases [funcref boost::contract::condition_if] should be sufficient, simpler and less verbose to use). + +The [funcref boost::contract::condition_if_c], [funcref boost::contract::call_if_c], and `.else_if_c` function templates work similarly to their counterparts without the `..._c` postfix above, but they take their condition template parameters as static boolean values instead of nullary boolean meta-functions. + +[heading Static-If Emulation (C++14)] + +The [funcref boost::contract::call_if] function template is a general facility and its use is not limited to programming contracts. +In fact, [funcref boost::contract::call_if] can be used together with C++14 generic lambdas to program statements similar to `static if` at least a function scope (`static if` was unsuccessfully proposed for addition to the C++ standard a number of different times, see __N3613__). +For example, consider the following implementation of `std::advance` that uses statements similar to `static if` but programmed via [funcref boost::contract::call_if] (see also [@../../example/features/call_if_cxx14.cpp =call_if_cxx14.cpp=]): + +[import ../example/features/call_if_cxx14.cpp] +[call_if_cxx14] + +This implementation is more concise, easier to read and maintain than the usual implementation of `std::advance` that uses tag dispatching. +[footnote +Boost.Hana (`boost::hana::if_`) can also be used to emulate function scope `static if` with C++14 generic lambdas. +] + +[endsect] + +[section Volatile Public Functions] + +This library allows to specify a different set of class invariants to be checked for volatile public member functions. +These /volatile class invariants/ are programmed in a public `const volatile` member function, named `invariant`, taking no argument, and returning `void` (see [macroref BOOST_CONTRACT_INVARIANT_FUNC] to name the invariant function differently from `invariant` and __Access_Specifiers__ to not have to declare it public). +Classes that do no have invariants to check for their volatile public functions, simply do not declare the `invariant() const volatile` member function. + +In general, `const volatile` qualified invariants work the same as `const` qualified invariant (see __Class_Invariants__) with the only difference that `volatile` and `const volatile` member functions check `const volatile` invariants while mutable (i.e., neither `const` nor `volatile` qualified) and `const` member functions check `const` invariants. +A given class can specify both `const volatile` and `const` qualified invariant member functions: +[footnote +*Rationale:* +Constructors and destructors check `const volatile` and `const` invariants in that order because the qualifier that limits the calls the least is checked first (note that a `const volatile` calls can be made on any object while `const` calls cannot be made on `volatile` non-`const` objects, in that sense the `const volatile` qualifier limits calls on an object less than `const` alone does). +This is consistent with `static` class invariants that are checked even before `const volatile` invariants (the `static` classifier limits calls even less than `const volatile` in the sense that an object is not even needed to make static calls). +] + +* Constructors check both `const volatile` and `const` qualified invariants in that order (at exit but only if no exception is thrown). +* Destructors check both `const volatile` and `const` qualified invariants (at entry). +* Both mutable and `const` public member functions check `const` qualified invariants (at entry and at exit). +* Both `volatile` and `const volatile` public member functions check `const volatile` qualified invariants (at entry and at exit). + +The above rules ensure that volatile class invariants are correctly checked (see also __Constructor_Calls__, __Destructor_Calls__, and __Public_Function_Calls__). +For example (see also [@../../example/features/volatile.cpp =volatile.cpp=]): + +[import ../example/features/volatile.cpp] +[volatile] + +While this library does not automatically check `const volatile` invariants for non-volatile functions, programmers can explicitly call the `const volatile` invariant function from the `const` invariant function if that makes sense for the contracts being specified (that way all public member functions `volatile` and not will check `const volatile` invariants): +[footnote +*Rationale:* +Note that while all public member functions can be made to check `const volatile` invariants, it is never possible to make volatile public member functions check `const` non-volatile invariants. +That is because both `const` and `volatile` can always be added but never stripped in C++ (a part from forcefully via `const_cast`) but `const` is always automatically added by this library in order to enforce contract constant-correctness (see __Constant_Correctness__). +That said, it would be incorrect for this library to also automatically add `volatile` and require all functions to check `const volatile` (not just `const`) invariants because only `volatile` members can be accessed from `const volatile` invariants so there could be many `const` (but not `const volatile`) members that are accessible from `const` invariants but not from `const volatile` invariants. +To avoid this confusion, this library has chosen to draw a clear dichotomy between `const` and `const volatile` invariants so that only volatile members check `const volatile` invariants and only non-volatile members check `const` (but not `const volatile`) invariants. +This is simple and should serve most cases. +If programmers need non-volatile members to also check `const volatile` invariants, they can explicitly do so by calling the `const volatile` invariant function from the `const` invariant function as shown in this documentation. +] + + class ``[^['class-type]]`` { + public: + void invariant() const { + ``[^['class-type]]`` const volatile& cv = *this; + cv.invariant(); // Call `void invariant() const volatile` below. + ... + } + + void invariant() const volatile { + ... + } + + ... + }; + +As usual, static class invariants can also be specified (see __Class_Invariants__) and private and protected member functions do not check any invariant (see __Private_and_Protected_Functions__). + +[endsect] + +[section Move Operations] + +As with all public operations of a class, also move operations should maintain class invariants (see also __Stroustrup13__, p. 520). +Specifically, C++ requires the following: + +* The moved-from object can be copy assigned. +* The moved-from object can be move assigned. +* The moved-from object can be destroyed (if not for anything else, this requires that class invariants are maintained by move operations because the destructor of the moved-from object requires class invariants to be satisfied at its destructor entry, as always with destructors see also __Destructor_Calls__). + +Thus both the move constructor and the move assignment operator need to maintain the class invariants of the moved-from object and their contracts can be programmed using [funcref boost::contract::constructor] and [funcref boost::contract::public_function] as always for constructors and public member functions, for example (see also [@../../example/features/move.cpp =move.cpp=]): + +[import ../example/features/move.cpp] +[move] + +This example assumes that it is possible to call the public member function `moved()` on the moved-from object. +This allows to make explicit the precondition that except for destructor, copy and move assignments all other public member functions cannot be called on a moved-from object. +This precondition is usually implicit in C++ (i.e., documented by the standard but not checked by the language at run-time). +If it is is not possible (e.g., due to some optimized implementation of the move operations) to have such a public `moved()` member function, the private `moved_` member (or similar) can be used to program class invariants and preconditions (and that will just relay on the usual implicit C++ assumption on moved-from object because users will not be able to fully check preconditions and class invariants before calling functions of a moved-from object). + +[note +The default move constructor and move assignment operator automatically generated by C++ will not check contracts. +Therefore, unless these operations are not public or they have no preconditions, no postconditions, and the class has no invariants, programmers should manually define them using [funcref boost::contract::constructor], [classref boost::contract::constructor_precondition], and [funcref boost::contract::public_function]. +(Same as for all other automatically generated operations.) +] + +[endsect] + +[section Unions] + +In C++, a `union` cannot have virtual member functions, bases classes, and cannot be used as a base class thus subcontracting ([classref boost::contract::virtual_], [macroref BOOST_CONTRACT_OVERRIDE], etc.) do not apply to unions. +Also a `union` cannot inherit from [classref boost::contract::constructor_precondition] (because it cannot have base classes) so such a class is used to declare a local object that checks constructor preconditions (see `pre` in the example below). +A part from that, this library is used as usual to program contracts for unions, for example (see also [@../../example/features/union.cpp =union.cpp=]): + +[import ../example/features/union.cpp] +[union] + +[endsect] + +[section Disable Contract Checking] + +Checking contracts adds run-time overhead and can slow down program execution (see also __Benefits_and_Costs__). +Therefore, programmers can define the following configuration macros (`-D` option in Clang and GCC, `/D` option in MSVC, etc.) to instruct this library to not check specific kind of contract conditions at run-time: + +* Define the [macroref BOOST_CONTRACT_NO_PRECONDITIONS] macro to not check preconditions. +* Define the [macroref BOOST_CONTRACT_NO_POSTCONDITIONS] macro to not check postconditions. +* Define the [macroref BOOST_CONTRACT_NO_EXCEPTS] macro to not check exception guarantees. +* Define the [macroref BOOST_CONTRACT_NO_ENTRY_INVARIANTS] macro to not check class invariants at call entries. +* Define the [macroref BOOST_CONTRACT_NO_EXIT_INVARIANTS] macro to not check class invariants at call exits. +* Or, define the [macroref BOOST_CONTRACT_NO_INVARIANTS] macro to not check class invariants at neither call entries or exits (provided for convenience, equivalent to defining both [macroref BOOST_CONTRACT_NO_ENTRY_INVARIANTS] and [macroref BOOST_CONTRACT_NO_EXIT_INVARIANTS]). +* Define the [macroref BOOST_CONTRACT_NO_CHECKS] macro to not check implementation checks. + +By default, none of these macros are defined so this library checks all contracts. +However, when the above macros are defined by the user, the implementation code of this library is internally optimized to minimize as much as possible any run-time and compile-time overhead associated with checking and compiling contracts (see __Disable_Contract_Compilation__ for techniques to completely remove any run-time and compile-time overhead associated with contract code). + +For example, programmers could decide to check all contracts during early development builds, but later check only preconditions and maybe entry invariants for release builds by defining [macroref BOOST_CONTRACT_NO_POSTCONDITIONS], [macroref BOOST_CONTRACT_NO_EXCEPTS], [macroref BOOST_CONTRACT_NO_EXIT_INVARIANTS], and [macroref BOOST_CONTRACT_NO_CHECKS]. + +[note +Old values can be used by both postconditions and exception guarantees so it is necessary to define both [macroref BOOST_CONTRACT_NO_POSTCONDITIONS] and [macroref BOOST_CONTRACT_NO_EXCEPTS] to disable old value copies. +] + +[endsect] + +[section Disable Contract Compilation (Macro Interface)] + +This library provides macros that can be used to completely disable compile-time overhead introduced by contracts but at the cost of manually programming `#ifndef` statements around contract code: + +* This library defines the [macroref BOOST_CONTRACT_NO_CONSTRUCTORS] macro if contract checking is disabled for constructors. +* This library defines the [macroref BOOST_CONTRACT_NO_DESTRUCTORS] macro if contract checking is disabled for destructors. +* This library defines the [macroref BOOST_CONTRACT_NO_PUBLIC_FUNCTIONS] macro if contract checking is disabled for public functions. +* This library defines the [macroref BOOST_CONTRACT_NO_FUNCTIONS] macro if contract checking is disabled for (non-public) functions. +* This library defines the [macroref BOOST_CONTRACT_NO_OLDS] macro if old value copies are disabled. +* This library defines the [macroref BOOST_CONTRACT_NO_ALL] macro if all kinds of contract checking are disabled. + +These macros are not configuration macros and they should not be defined directly by the user (otherwise this library will generate a compile-time error). +Instead, these macros are automatically defined by this library based on users defining the `BOOST_CONTRACT_NO_...` macros listed in __Disable_Contract_Checking__. + +Alternatively, this library provides a macro-based interface [headerref boost/contract_macro.hpp] that can also be used to completely disable compile-time overhead of contract code. +The macro interface is more concise than using `#ifndef` statements but it makes the contract code and eventual compiler errors more cryptic (because all the macro code will expand on a single line number, etc. as always with C++ macros). + +The following example illustrates both the use of the macro interface and of `#ifndef` statements to selectively disable not just contract checking at run-time but contract code compilation altogether (see also [@../../example/features/ifdef_macro.cpp =ifdef_macro.cpp=] and [@../../example/features/ifdef.pp =ifdef.cpp=]): + +[import ../example/features/ifdef_macro.cpp] +[import ../example/features/ifdef.cpp] +[table +[ [Macro Interface] [Code Interface] ] +[ [[ifdef_macro_function]] [[ifdef_function]] ] +] + +The same is done to disable contract code complication for private and protected functions. +The [macroref BOOST_CONTRACT_OLD_PTR_IF_COPYABLE] macro is provided to handle non-copyable old value types. +For constructors, destructors, and public functions instead (see also [@../../example/features/ifdef_macro.cpp =ifdef_macro.cpp=] and [@../../example/features/ifdef.pp =ifdef.cpp=]): + +[table +[ [Macro Interface] [Code Interface] ] +[ [[ifdef_macro_class]] [[ifdef_class]] ] +] + +The authors of this library do not recommend to use these techniques unless strictly necessary because they both make the contract code more verbose, less readable, and can cause cryptic compiler error messages. +In most cases, the compile-time overhead of contracts should not represent an issue and it should be sufficient to disable contract checking at run-time as indicated in __Disable_Contract_Checking__. + +[endsect] + +[section Separate Body Implementation] + +Contracts are part of the program specification and not of its implementation (see also __Specification_vs_Implementation__). +However, this library uses function definitions to program the contracts so contract code appears together with the function implementation code. +This is not ideal (even if contract code programmed with this library must always appear at the very top of the function definition so programmers will easily be able to distinguish it from the rest of function implementation so this might not be real problem in practise). + +In some cases, it might be desirable to completely separate the contract code (function specification) from the function body code (function implementation). +For example, this could be necessary for software that ships only header files and pre-compiled source code to its users (notably, that cannot be done for template code in C++). +If the contracts are programmed in the function definitions that are pre-compiled with the source code, users will not be able to inspect the contract code to understand semantics and usage of the functions (again, this might not be a real problem in practice for example if contract code is already somehow extracted from the source code and presented as part of the documentation of the shipped software). + +In such cases, the function implementation can be programmed in an extra /body function/ (e.g., named `..._body`) that is defined in the source code. +The original function definition remains in the header files instead, it contains the contract and then simply calls the extra body function. +This technique allows to keep the contract code in header files while separating the body implementation code to source files but at the cost of programmers writing an extra function declaration for the body function (with the limitation that constructor member initialization lists must also be programmed in the header files because that is where the constructors that call their extra body functions will be actually defined). + +For example, the following header file only contains function declarations and contract code (function specifications) and constructor member initializations (see also [@../../example/features/separate_body.hpp =separate_body.hpp=]): + +[import ../example/features/separate_body.hpp] +[separate_body_hpp] + +Instead, the function bodies (function implementations) is programmed in a separate source file (see also [@../../example/features/separate_body.cpp =separate_body.cpp=]): + +[import ../example/features/separate_body.cpp] +[separate_body_cpp] + +The same technique can be used for non-member, private, protected functions, etc. + +[note +When contracts are programmed in separate =.cpp= files and also /all/ this library headers are `#include`d only from the users' =.cpp= files, then these =.cpp= files can be compiled disabling specific contract checking (for example, [macroref BOOST_CONTRACT_NO_POSTCONDITIONS], [macroref BOOST_CONTRACT_NO_EXCEPTS], and [macroref BOOST_CONTRACT_NO_EXIT_INVARIANTS], see __Disable_Contract_Checking__). +Then the code in these =.cpp= files will always have such contract checking disabled even when linked to some other user code that might have been compiled with a different set of contracts disabled (i.e., a different set of `BOOST_CONTRACT_NO_...` macros defined). +This technique might be useful to ship pre-compiled object files (e.g., for a library) that will never check some contracts (e.g., postconditions, exception guarantees, and exit invariants) regardless of the definition of the `BOOST_CONTRACT_NO_...` macros used to compile code that links against the shipped object files. + +On the contrary, if contracts are programmed in header files and this library headers are `#include`d in the header files that are being shipped, then end users can enable or disables contract checking of the shipped code by defining the `BOOST_CONTRACT_NO_...` macros when they compile the shipped header files as part of their code. +This technique might be useful in other situations when programmers that ship code want to leave it up the their end users to decide which contracts of the shipped code should be checked at run-time. +] + +[endsect] + +[section No Lambda Functions (No C++11)] + +This section shows how to use this library without C++11 lambda functions. +This has some advantages: + +* It allows to use this library on compilers that do not support C++11 lambda functions (essentially most C++03 compilers can be used in that case, see __No_Macros__ to also avoid using variadic macros). +* Contract functions (see the `..._precondition`, `..._old`, and `..._postcondition` functions in the example below) can be programmed to fully enforce constant-correctness and other contract requirements at compile-time (see also __Constant_Correctness__). +[footnote +If C++ allowed lambda functions to capture variables by constant reference (e.g., `[const&] (...) { ... }` or `[const& `[^['variable-name]]`] (...) { ... }`) also lambdas could be used to program contract functors that fully enforce __Constant_Correctness__ at compile-time. +Note that C++11 lambda allows to capture variables by value (`[=] (...) { ... }` and `[`[^['variable-name]]`] (...) { ... }`), these value captures are `const` (unless the lambda is explicitly declared `mutable`) but they are not suitable to program postconditions and exception guarantees using this library (because those require capturing by reference, see __Postconditions__ and __Exception_Guarantees__), plus they introduce an extra copy that might be too expensive in general. +] +* Contract specifications are automatically separated from function body implementations (see __Separate_Body_Implementation__). + +However, not using C++11 lambda functions comes to the significant cost of having to manually write a great deal of boiler-plate code, for example (see also [@../../example/features/no_lambdas.hpp =no_lambdas.hpp=] and [@../../example/features/no_lambdas.cpp =no_lambdas.cpp=]): + +[import ../example/features/no_lambdas.hpp] +[no_lambdas_hpp] + +[import ../example/features/no_lambdas.cpp] +[no_lambdas_cpp] + +If programmers also want to fully enforce all contract programming constant-correctness requirements at compile-time, they should follow these rules when programming the contract functions (see also __Constant_Correctness__): + +* Precondition functions (i.e., the `..._precondition` functions in the example above) can take their arguments either by `const` value or by `const&`, and they should be either `static` or `const` member functions. +* Postcondition functions (i.e., the `..._postcondition` functions in the example above) should take their arguments by `const&`, and they should be either `static` or `const` member functions. +* Old value functions (i.e., the `..._old` functions in the example above) should take their arguments by `const&` a part from old value pointers that should be taken by `&` (so only old value pointers can be modified), and they should be either `static` or `const` member functions. +* Constructor precondition and old value functions should be `static` (because constructor preconditions and old values cannot access the object `this`, see also __Constructor_Calls__). +* Destructor postcondition functions should be `static` (because destructor postconditions cannot access the object `this`, see also __Destructor_Calls__). + +Note that the extra contract functions also allow to program only the contract code in the header file (see also __Specification_vs_Implementation__). +All function body implementation code was instead programmed in the source file (including the constructor member initialization list, that could not be done with the technique shown in __Separate_Body_Implementation__). +[footnote +In this example, `bind` was used to generate nullary functors from the contract functions. +As always with `bind`, `cref` and `ref` must be used to bind arguments by `const&` and `&` respectively, plus it might be necessary to explicitly `static_cast` the function pointer passed to `bind` in case the bound function name is overloaded. +] +Also note that the contract functions can always be declared `private` if programmers need to exactly control the public members of the class (this was not done in this example only for brevity, see also __Access_Specifiers__). + +Alternatively, on compilers that do not support C++11 lambda functions but that support type-of (either native as an extension or via emulation, these should be most recent C++03 compilers), [@http://www.boost.org/doc/libs/release/libs/local_function/doc/html/index.html Boost.LocalFunction] can be used to program the contract functions, for example (see also [@../../example/features/no_lambdas_local_func.cpp =no_lambda_local_func.cpp=]): + +[import ../example/features/no_lambdas_local_func.cpp] +[no_lambdas_local_func] + +This code is somewhat less verbose than the previous example (about 30% less lines of code) but the contract code is hard to ready. +Other libraries could also be used to program the contract functions without C++11 lambda functions (Boost.Lambda, Boost.Fusion, etc.) but like the techniques shown above, they will all result in contract code more verbose, or harder to read and maintain than the contract code programmed using C++11 lambda functions. + +The authors think this library is most useful when used together with C++11 lambda functions. + +[endsect] + +[section No Macros (No C++11)] + +It is possible to specify contracts without using most of this library macros and programming the related code manually instead. +The only macro that cannot be programmed manually is [macroref BOOST_CONTRACT_OVERRIDE] (and the similar [macroref BOOST_CONTRACT_OVERRIDES] and [macroref BOOST_CONTRACT_NAMED_OVERRIDE]). + +[note +Some of this library macros are variadic macros, others are not (see below). +Variadic macros were officially added to the language since C++11 but most compilers have been supporting variadic macros as an extension for a long time, plus essentially all compilers that support C++11 lambda functions also support C++11 variadic macros (and this library might rarely be used without the convenience of C++11 lambda functions, see also __No_Lambda_Functions__). +Therefore, the following can be considered mainly a curiosity because programmers should seldom need to use this library without using its macros. +] + +[heading Overrides] + +As shown in __Public_Function_Overrides__ and __Named_Overrides__, this library provides the [macroref BOOST_CONTRACT_OVERRIDE] and [macroref BOOST_CONTRACT_NAMED_OVERRIDE] macros to program contracts for overriding public functions. +These macros cannot be programmed manually but they are not variadic macros so programmers should be able to use them on all C++ compilers. +[footnote +*Rationale:* +These macros expand SFINAE-based introspection templates that are too complex to be programmed manually by users (that remains the case even if C++14 generic lambdas were to be used here). +] +The [macroref BOOST_CONTRACT_OVERRIDES] macro is a variadic macro instead but programmes can manually repeat the non-variadic macro [macroref BOOST_CONTRACT_OVERRIDE] for each overriding public function name on compilers that do not support variadic macros. + +[heading Assertions (Not Variadic)] + +As shown in __Preconditions__, __Postconditions__, __Exception_Guarantees__, __Class_Invariants__, etc. this library provides the [macroref BOOST_CONTRACT_ASSERT] macro to assert contract conditions. +This is not a variadic macro and programmers should be able to use it on all C++ compilers. +In any case, the invocation `BOOST_CONTRACT_ASSERT(`[^['condition]]`)` simply expands to code equivalent to the following: + + if(!(``[^['condition]]``)) { + throw boost::contract::assertion_failure(__FILE__, __LINE__, + BOOST_PP_STRINGIZE(``[^['condition]]``)); + } + +In fact, this library considers any exception thrown from within preconditions, postconditions, exception guarantees, and class invariants as a contract failure and reports it calling the related contract failure handler ([funcref boost::contract::precondition_failure], etc., see also __Throw_on_Failure__). +If there is a need for it, programmers can always program contract assertions that throw specific exceptions as follow (see [@../../example/features/throw_on_failure.cpp =throw_on_failure.cpp=] for an example): + + if(!``[^['condition]]``) throw ``[^['exception-object]]``; + +However, using [macroref BOOST_CONTRACT_ASSERT] is convenient because it always allows this library to show an informative message in case of assertion failure containing the assertion code, file name and line number, etc. + +[heading Base Types (Variadic)] + +As shown in __Base_Classes__, this library provides the [macroref BOOST_CONTRACT_BASE_TYPES] variadic macro to declare the `base_types` member type that lists all public bases of a derived class. +Programmers can also declare `base_types` without using [macroref BOOST_CONTRACT_BASE_TYPES] at the cost of writing a bit more code manually, for example (see also [@../../example/features/base_types_no_macro.cpp =base_types_no_macro.cpp=]): + +[import ../example/features/base_types_no_macro.cpp] +[base_types_no_macro] + +The `base_types` member type must be a `boost::mpl::vector` which must list /only/ `public` base classes (because only public bases subcontract, see also __Function_Calls__), and in the same order these public base classes appear in the derived class inheritance list. +If the [macroref BOOST_CONTRACT_BASE_TYPES] macro is not used, it is the responsibility of the programmers to maintain the correct list of bases in the `boost::mpl::vector` each time the derived class inheritance list changes (this might complicate maintenance). + +In general, it is recommended to use the [macroref BOOST_CONTRACT_BASE_TYPES] macro whenever possible. + +[heading Old Values (Variadic)] + +As shown in __Old_Values__, this library provides the [macroref BOOST_CONTRACT_OLDOF] variadic macro to assign old value copies. +Programmers can also assign old values without using [macroref BOOST_CONTRACT_OLDOF] at the cost of writing a bit more code manually, for example (see also [@../../example/features/old_no_macro.cpp =old_no_macro.cpp=]): + +[import ../example/features/old_no_macro.cpp] +[old_no_macro] + +The ternary operator `boost::contract::copy_old(v) ? size() : boost::contract::null_old()` must be used here to avoid evaluating and copying the old value expression `size()` when [funcref boost::contract::copy_old] returns `false` because old values are not being copied (postcondition and exception guarantees checking is disabled at run-time, an overridden virtual function call is not checking postconditions or exception guarantees yet, etc.). +The enclosing [funcref boost::contract::make_old] copies the old value expression and creates an old value pointer. +Otherwise, [funcref boost::contract::null_old] indicates that a null old value pointer should be created. + +The [funcref boost::contract::make_old] and [funcref boost::contract::copy_old] functions are used exactly as above but without the extra `v` parameter when they are called from within non-virtual functions (see also __Public_Function_Overrides__). +The old value pointer returned by [funcref boost::contract::make_old] can be assigned to either [classref boost::contract::old_ptr] or [classref boost::contract::old_ptr_if_copyable] (see also __Old_Value_Requirements__). + +In general, it is recommended to use the [macroref BOOST_CONTRACT_OLDOF] macro whenever possible. + +[heading Macro Interface (Variadic)] + +Almost all macros defined in [headerref boost/contract_macro.hpp] are variadic macros. +On compilers that do not support variadic macros, programmers can manually disable contract code compilation using `#ifndef BOOST_CONTRACT_NO_...` statements as shown in __Disable_Contract_Compilation__. + +[endsect] + +[endsect] + diff --git a/doc/extras.qbk b/doc/extras.qbk deleted file mode 100644 index 4781e32..0000000 --- a/doc/extras.qbk +++ /dev/null @@ -1,302 +0,0 @@ - -[/ Copyright (C) 2008-2016 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] - -[section Extras] - -This section can be consulted selective for specific topics of interest. - -[section Move Operations] - -As with all public operations of a class, also move operations should maintain class invariants (see also __Stroustrup13__, p. 520). -Specifically, C++ requires the following: - -* The moved-from object can be copy assigned. -* The moved-from object can be move assigned. -* The moved-from object can be destroyed. -[footnote -If not anything else, this requires that class invariants are maintained by move operations because the destructor of the moved-from object requires that class invariants are true at its entry (as always with destructors, see also __Destructor_Calls__). -] - -Thus both the move constructor and the move assignment operator need to maintain the class invariants of the moved-from object and their contracts can be programmed using [funcref boost::contract::constructor] and [funcref boost::contract::public_function] as always for constructors and public member functions, for example (see also [@../../example/features/move.cpp =move.cpp=]): - -[import ../example/features/move.cpp] -[move] - -This example assumes that it is possible to call the public member function `move()` on the moved-from object. -This allows to make explicit the precondition that except for destructor, copy and move assignments all other public member functions cannot be called on a moved-from object. -This precondition is usually implicit in C++ (i.e., documented by the standard but not checked by the language at run-time). -If it is is not possible (e.g., due to some optimized implementation of the move operations) to have such a public `move()` member function, the private `moved_` member (or similar) can be used to program class invariants and preconditions (and that will just relay on the usual implicit C++ assumption on moved-from object because users will not be able to fully check preconditions and class invariants before calling functions of a moved-from object). - -[note -The default move constructor and move assignment operator automatically generated by C++ will not check contracts. -Therefore, unless these operations are not public or they have no preconditions, no postconditions, and the class has no invariants, programmers should manually define them using [funcref boost::contract::constructor], [classref boost::contract::constructor_precondition], and [funcref boost::contract::public_function]. -(Same for all other automatically generated operations.) -] - -[endsect] - -[section Unions] - -In C++, a `union` cannot have virtual member functions, bases classes, and cannot be used as a base class thus subcontracting ([classref boost::contract::virtual_], [macroref BOOST_CONTRACT_OVERRIDE], etc.) do not apply to unions. -Also a `union` cannot inherit from [classref boost::contract::constructor_precondition] (because it cannot have base classes) so such a class is used to declare a local object that checks constructor preconditions (see `pre` in the example below). -A part from that, this library is used as usual to program contracts for unions, for example (see also [@../../example/features/union.cpp =union.cpp=]): - -[import ../example/features/union.cpp] -[union] - -[endsect] - -[section Volatile Class Invariants] - -This library allows to specify a different set of class invariants to be checked for public volatile member functions. -These /volatile class invariants/ are programmed in a public member function `const volatile` qualified and named `invariant` (see [macroref BOOST_CONTRACT_INVARIANT] to name the invariant function differently from `invariant` and __Access__ to not have to declare it public). - -In general, `const volatile` qualified invariants work the same as `const` qualified invariant (see __Class_Invariants__) with the only difference that `volatile` and `const volatile` member functions check `const volatile` invariants while mutable (i.e., neither `const` nor `volatile` qualified) and `const` member functions check `const` invariants. -A given class can specify both `const volatile` and `const` qualified invariant member functions: -[footnote -*Rationale:* -Constructors and destructors check `const volatile` and `const` invariants in that order because the qualifier that limits the calls the least is checked first (note that a `const volatile` calls can be made on any object while `const` calls cannot be made on `volatile` non-`const` objects, in that sense the `const volatile` qualifier limits calls on an object less than `const` alone does). -This is consistent with `static` class invariants that are checked even before `const volatile` invariants (the `static` classifier limits calls even less than `const volatile` in the sense that an object is not even needed to make static calls). -While there is a more important reason to check `static` invariants before all other invariants (see __Contract_Programming_Overview__), the above is the only reason why this library checks `const volatile` invariants before `const` invariants for constructors and destructors. -] - -* Constructors check both `const volatile` and `const` qualified invariants in that order (at exit if no exception is thrown). -* Destructors check both `const volatile` and `const` qualified invariants (at entry). -* Both mutable and `const` public member functions check `const` qualified invariants (at entry and at exit if no exception is thrown). -* Both `volatile` and `const volatile` public member functions check `const volatile` qualified invariants (at entry and at exit if no exception is thrown). - -This ensures that volatile class invariants are correctly checked (see also __Constructor_Calls__, __Destructor_Calls__, and __Public_Function_Calls__). -For example (see also [@../../example/features/volatile.cpp =volatile.cpp=]): - -[import ../example/features/volatile.cpp] -[volatile] - -While this library does not automatically check `const volatile` invariants for non-volatile functions, programmers can explicitly call the `const volatile` invariant function from the `const` invariant function if that makes sense for the contracts being specified (that way all public member functions `volatile` and not will check `const volatile` invariants): -[footnote -*Rationale:* -Note that while all public member functions can be made to check `const volatile` invariants, it is never possible to make volatile public member functions check `const` non-volatile invariants. -That is because both `const` and `volatile` can always be added but never stripped in C++ (a part from forcefully via `const_cast`) but `const` is always automatically added by this library in order to enforce contract constant-correctness (see __Constant_Correctness__). -That said, it would be incorrect for this library to also automatically add `volatile` and require all functions to check `const volatile` (not just `const`) invariants because only `volatile` members can be accessed from `const volatile` invariants so there could be many `const` (but not `const volatile`) members that are accessible from `const` invariants but not from `const volatile` invariants. -To avoid this confusion, this library has chosen to draw a clear dichotomy between `const` and `const volatile` invariants so that only volatile members check `const volatile` invariants and only non-volatile members check `const` (but not `const volatile`) invariants. -This is simple and should serve most cases. -If programmers need non-volatile members to check `const volatile` invariants, they can explicitly do so by calling the `const volatile` invariant function from the `const` invariant function as shown in this documentation. -] - - class ``[^['class-type]]`` { - public: - void invariant() const { - ``[^['class-type]]`` const volatile& cv = *this; - cv.invariant(); // Call `void invariant() const volatile` below. - ... - } - - void invariant() const volatile { - ... - } - - ... - }; - -As usual, static class invariants can also be specified (see __Static_Class_Invariants__) and private and protected member functions do not check any invariant (see __Private_and_Protected_Functions__). - -[endsect] - -[section Disable Contract Compilation (Macro Interface)] - -This library provides macros that can be used to disable compile-time overhead introduced by contracts but at the cost of manually programming `#ifdef` statements around contract code. -The authors of this library do not recommend to use this practice unless strictly necessary because it makes the contract code more verbose, less readable, and in most applications the compile-time overhead of contracts should not represent an issue (it should be sufficient to disable contract checking at run-time as indicated before). - -In any case, the following example illustrates how to completely disable contract code compilation for non-member functions (see also [@../../example/features/ifdef_macro.cpp =ifdef_macro.cpp=] and [@../../example/features/ifdef.pp =ifdef.cpp=]): - -[import ../example/features/ifdef_macro.cpp] -[import ../example/features/ifdef.cpp] -[table -[ [Macro Interface] [Code Interface] ] -[ [[ifdef_macro_function]] [[ifdef_function]] ] -] - -The same is done to disable contract code complication for private and protected functions. -For constructors, destructors, and public functions instead (see also [@../../example/features/ifdef_macro.cpp =ifdef_macro.cpp=] and [@../../example/features/ifdef.pp =ifdef.cpp=]): - -[table -[ [Macro Interface] [Code Interface] ] -[ [[ifdef_macro_class]] [[ifdef_class]] ] -] - -As shown by the examples above: - -* The [macroref BOOST_CONTRACT_NO_PRECONDITIONS] macro is defined by programmers and it can be used in `#ifdef` statements to disable compilation of preconditions, including constructor preconditions ([classref boost::contract::constructor_precondition]). -* The [macroref BOOST_CONTRACT_NO_POSTCONDITIONS] macro is defined by programmers and it can be used in `#ifdef` statements to disable compilation of postconditions, old value declarations, and old value assignments at body (`.old(...)`). -* The [macroref BOOST_CONTRACT_NO_INVARIANTS] macro is defined by programmers (or it will be automatically defined by this library if both [macroref BOOST_CONTRACT_NO_ENTRY_INVARIANTS] and [macroref BOOST_CONTRACT_NO_EXIT_INVARIANTS] are defined) and it can be used in `#ifdef` statements to disable compilation of class invariants (including static and volatile class invariants). -Also the [macroref BOOST_CONTRACT_NO_ENTRY_INVARIANTS] and [macroref BOOST_CONTRACT_NO_EXIT_INVARIANTS] macros are defined by programmers (or they will be both automatically defined by this library if [macroref BOOST_CONTRACT_NO_INVARIANTS] is defined) but these macros are not directly used to disable contract code compilation (only contract code run-time checking). -* The [macroref BOOST_CONTRACT_NO_CONSTRUCTORS] macro is automatically defined by this library (a compile-time error will be reported if programmes try to manually define this macro) and it can be used in `#ifdef` statements to disable compilation of constructor contract guards. -* The [macroref BOOST_CONTRACT_NO_DESTRUCTORS] macro is automatically defined by this library (a compile-time error will be reported if programmers try to manually define this macro) and it can be used in `#ifdef` statements to disable compilation of destructor contract guards. -* The [macroref BOOST_CONTRACT_NO_PUBLIC_FUNCTIONS] macro is automatically defined by this library (a compile-time error will be reported if programmers try to manually define this macro) and it can be used in `#ifdef` statements to disable compilation of public member function contract guards, base type `typedef`, extra [classref boost::contract::virtual_] function parameters, and [macroref BOOST_CONTRACT_OVERRIDE] declarations. -* The [macroref BOOST_CONTRACT_NO_FUNCTIONS] macro is automatically defined by this library (a compile-time error will be reported if programmers try to manually define this macro) and it can be used in `#ifdef` statements to disable compilation of contract guards for non-member functions as well as private and protected functions. -* The [macroref BOOST_CONTRACT_NO_ALL] macro is automatically defined by this library (a compile-time error will be reported if programmers try to manually define this macro) and it can be used in `#ifdef` statements to disable [classref boost::contract::access] friendship declarations and also inclusions of [headerref boost/contract.hpp] (some of the other macros listed here can be used to selectively disable inclusion of =boost/contract/*.hpp= headers when they are used instead of [headerref boost/contract.hpp].) - -[endsect] - -[section Implementation Checks] - -[endsect] - -[section Separate Body Implementation (No C++11 Lambdas)] - -Contracts are part of the program specification and not of its implementation (see also __Specification_and_Implementation__). -However, this library uses function definitions to program the contracts so contract code appears together with the function implementation code. -This is not ideal, but contract code programmed with this library must always appear at the very top of the function definition so programmers will easily be able to distinguish it from the rest of function implementation code (so this might not be real problem in practise). - -In some cases, it might be desirable to completely separate the contract code (function specification) from the function body code (function implementation). -For example, this could be necessary for software that ships only header files and pre-compiled source code to its users (notably, that cannot be done for template code in C++). -If the contracts are programmed in the function definitions that are pre-compiled with the source code, users will not be able to inspect the contract code to understand semantics and usage of the functions (again, this might not be a real problem in practice for example if contract code is already somehow extracted from the source code and presented as part of the documentation of the shipped software). - -In such cases, the function implementation can be programmed in an extra /body function/ (e.g., named `..._body`) that is defined in the source code. -The original function definition remains in the header files instead, it programs the contract and simply calls the extra body function. -At the cost of programmers writing an extra function declaration for the body function, this technique allows to keep the contract code in header files while separating the body implementation code to source files (with the limitation that constructor member initialization lists must still be programmed in the header files because that is where the constructors are actually defined). - -For example, the following header file only contains function declarations and contract code (function specifications) and constructor member initializations (see also [@../../example/features/separate_body.hpp =separate_body.hpp=]): - -[import ../example/features/separate_body.hpp] -[separate_body_hpp] - -Instead, the function bodies (function implementations) is programmed in a separate source file (see also [@../../example/features/separate_body.cpp =separate_body.cpp=]): - -[import ../example/features/separate_body.cpp] -[separate_body_cpp] - -The same technique can be used for non-member, private, and protected functions. - -[note -When contracts are programmed in a separate =.cpp= files and also /all/ these library headers are `#include`d only from =.cpp= files, then the =.cpp= files can be compiled disabling specific contract checking (for example, [macroref BOOST_CONTRACT_NO_POSTCONDITIONS] and [macroref BOOST_CONTRACT_NO_EXIT_INVARIANTS], see __Disable_Contract_Checking__). -The user code that will link to these =.cpp= files not be able to -Then the code in these =.cpp= files will always have such contract checking disabled even when linked to some other user code that might have been compiled with a different set of disable contracts (i.e., a different `BOOST_CONTRACT_NO_...` defined). -This technique might be useful to ship a pre-compiled set of object files (e.g., for a library) that will never check some contracts (e.g., postconditions and exit invariants) regardless of the definition of the `BOOST_CONTRACT_NO_...` macros used to compile code that uses such object files. - -On the contrary, if contracts are programmed in header files and this library headers are `#include`d in header files that are being shipped, then end users enable or disables contracts of the shipped code by defining `BOOST_CONTRACT_NO_...` when they compiled the shipped header files as part of their code. -This technique might be useful in other situations when programmers that ship code want instead to leave it up the their end users to decide which contracts in the shipped code should be checked at run-time. -] - -[endsect] - -[section No Macros (No C++11)] - -It is possible to specify contracts without using this library macros and programming the related code manually instead (a part from [macroref BOOST_CONTRACT_OVERRIDE], [macroref BOOST_CONTRACT_OVERRIDES], and [macroref BOOST_CONTRACT_NAMED_OVERRIDE] that cannot be programmed manually). - -Some of this library macros are variadic macros, others are not (see below). -Variadic macros were officially added to the language since C++11 but most compilers have been supporting variadic macros as an extension for a long time, plus essentially all compilers that support C++11 lambda functions also support C++11 variadic macros (and this library might rarely be used without the convenience of C++11 lambda functions, see also __No_Lambda_Functions__). -Therefore, the following can be considered mainly a curiosity because programmers should seldom need to use this library without using its macros. - -[heading Overrides] - -As shown in __Public_Function_Overrides__ and __Named_Overrides__, this library provides the [macroref BOOST_CONTRACT_OVERRIDE] and [macroref BOOST_CONTRACT_NAMED_OVERRIDE] macros to program contracts for overriding public functions. -These macros cannot be programmed manually but they are not variadic macros so programmers should be able to use them on all C++ compilers. -[footnote -*Rationale:* -These macros expand SFINAE-based introspection templates that cannot be reasonably programmed by users (that remains the case even if C++14 generic lambdas were to be used here). -] -The [macroref BOOST_CONTRACT_OVERRIDES] macro is a variadic macro instead but programmes can manually repeat the non-variadic macro [macroref BOOST_CONTRACT_OVERRIDE] for each overriding public function name on compilers that do not support variadic macros. - -[heading Assertions (Not Variadic)] - -As shown in __Preconditions__, __Postconditions__, __Class_Invariants__, etc. this library provides the [macroref BOOST_CONTRACT_ASSERT] macro to assert contract conditions. -This is not a variadic macro and programmers should be able to use it on all C++ compilers. -However, the macro invocation `BOOST_CONTRACT_ASSERT(`[^['condition]]`)` simply expands to code equivalent to the following: - - if(!``[^['condition]]``) { - throw boost::contract::assertion_failure(__FILE__, __LINE__, - BOOST_PP_STRINGIZE(``[^['condition]]``)); - } - -That is because this library considers any exception thrown from within preconditions, postconditions, and class invariants as a contract failure and reports it calling the related contract failure handler ([funcref boost::contract::precondition_failure], etc., see also __Throw_on_Failure__). -In fact, if there is a need for it, programmers can always program contract assertions that throw an exception as follow (see [@../../example/features/throw_on_failure.cpp =throw_on_failure.cpp=] for an example): - - if(!``[^['condition]]``) throw ``[^['exception-type]]``(...); - -However, using [macroref BOOST_CONTRACT_ASSERT] always allows this library to show detailed information about the assertion code, its file and line number, etc. - -[heading Base Types (Variadic)] - -As shown in __Base_Classes__, this library provides the [macroref BOOST_CONTRACT_BASE_TYPES] variadic macro to declare the `base_types` member type that lists all public bases of a derived class. -Programmers can also declare `base_types` without using [macroref BOOST_CONTRACT_BASE_TYPES] at the cost of writing a bit more code manually, for example (see also [@../../example/features/base_types_no_macros.cpp =base_types_no_macros.cpp=]): - -[import ../example/features/base_types_no_macros.cpp] -[base_types_no_macros] - -The `base_types` member type must be a `boost::mpl::vector` and it must list /only/ `public` base classes (because only public bases subcontract, see also __Function_Calls__). -If the [macroref BOOST_CONTRACT_BASE_TYPES] macro is not used, it is the responsibility of the programmers to maintain the correct list of bases in the `boost::mpl::vector` each time the derived class inheritance list changes (this might complicate maintenance). -In general, it is recommended to use the [macroref BOOST_CONTRACT_BASE_TYPES] macro if possible. - -[heading Old Values (Variadic)] - -As shown in __Old_Values__, this library provides the [macroref BOOST_CONTRACT_OLDOF] variadic macro to assign old value copies. -Programmers can also assign old values without using [macroref BOOST_CONTRACT_OLDOF] at the cost of writing a bit more code manually, for example (see also [@../../example/features/old_no_macros.cpp =old_no_macros.cpp=]): - -[import ../example/features/old_no_macros.cpp] -[old_no_macros] - -The ternary operator `boost::contract::copy_old(v) ? size() : boost::contract::null_old()` must be used here to avoid evaluating and copying the old value expression `size()` when [funcref boost::contract::copy_old] returns `false` because old values are not being copied (postcondition checking is disable at run-time, an overridden virtual function call is not checking postconditions yet, etc.). -The enclosing [funcref boost::contract::make_old] copies the old value expression and creates an old value pointer, while [funcref boost::contract::null_old] indicates when a null old value pointer should be created. - -The [funcref boost::contract::make_old] and [funcref boost::contract::copy_old] functions are used exactly as above but without the extra `v` parameter when they are called from within non-virtual functions (see also __Public_Function_Overrides__). -The old value pointer returned by [funcref boost::contract::make_old] can be assigned to either [classref boost::contract::old_ptr] or [classref boost::contract::noncoyable_old_ptr] (see also __Old_Value_Requirements__). - -In general, it is recommended to use the [macroref BOOST_CONTRACT_OLDOF] macro if possible. - -[endsect] - -[section No Lambda Functions (No C++11)] - -This section shows how to use this library without C++11 lambda functions. -This has some advantages: - -* It allows to use this library on compilers that do not support C++11 lambda functions (essentially most C++03 compilers can be used, see __No_Macros__ to also avoid using variadic macros). -* Contract functions (see the `..._precondition`, `..._old`, and `..._postcondition` functions in the example below) can be programmed to fully enforce constant-correctness and other contract requirements at compile-time (see also __Constant_Correctness__). -[footnote -If C++ allowed lambda functions to capture variables by constant reference (e.g., `[const&] (...) { ... }` or `[const& `[^['variable-name]]`] (...) { ... }`) also lambdas could be used to program contract functors that fully enforce __Constant_Correctness__ at compile-time. -Note that C++11 lambda allows to capture variables by value (`[=] (...) { ... }` and `[`[^['variable-name]]`] (...) { ... }`), these value captures are `const` (unless the lambda is explicitly declared `mutable`) but they are not suitable to program postconditions using this library (see __Postconditions__), plus they introduce an extra copy that might be too expensive in general. -] -* Contracts are separated from function body implementations (see also __Specification_and_Implementation__ and __Separate_Body_Implementation__). - -However, not using C++11 lambda functions comes to the significant cost of having to manually write a great deal of extra code to program the contract functions, for example (see also [@../../example/features/no_lambdas.hpp =no_lambdas.hpp=] and [@../../example/features/no_lambdas.cpp =no_lambdas.cpp=]): - -[import ../example/features/no_lambdas.hpp] -[no_lambdas_hpp] - -[import ../example/features/no_lambdas.cpp] -[no_lambdas_cpp] - -If programmers also want to fully enforce all contract programming constant-correctness requirements at compile-time, they should follow these rules when programming the contract functions (see also __Constant_Correctness__): - -* Precondition functions (i.e., the `..._precondition` functions in the example above) can take their arguments either by `const` value or by `const&`, and they should be either `static` or `const` member functions. -* Postcondition functions (i.e., the `..._postcondition` functions in the example above) should take their arguments by `const&`, and they should be either `static` or `const` member functions. -* Old value functions (i.e., the `..._old` functions in the example above) should take their arguments by `const&` a part from old value pointers that should be taken by `&` (so only old value pointers can be modified), and they should be either `static` or `const` member functions. -* Constructor precondition and old value functions should be `static` (because constructor preconditions and old values cannot access the object `this`, see also __Constructor_Calls__). -* Destructor postcondition functions should be `static` (because destructor postconditions cannot access the object `this`, see also __Destructor_Calls__). - -Note that the extra contract functions also allow to program only the contract code in the header file (see also __Specification_and_Implementation__). -All function body implementation code was instead programmed in the source file (including the constructor member initialization list, that could not be done with the technique shown in __Separate_Body_Implementation__). -[footnote -In this example, `bind` was used to generate nullary functors from the contract functions. -As always with `bind`, `cref` and `ref` must be used to bind arguments by `const&` and `&` respectively, plus it might be necessary to explicitly `static_cast` the function pointer passed to `bind` in case the bound function name is overloaded. -] -Also note that the contract functions can always be declared `private` if programmers need to exactly control the public members of the class (this was not done in this example only for brevity, see also __Access__). - -Alternatively, on compilers that do not support C++11 lambda functions but that support type-of (either native as an extension or via emulation, these should be most recent C++03 compilers), [@http://www.boost.org/doc/libs/release/libs/local_function/doc/html/index.html Boost.LocalFunction] can be used to program the contract functions, for example (see also [@../../example/features/no_lambdas_local_func.cpp =no_lambda_local_func.cpp=]): - -[import ../example/features/no_lambdas_local_func.cpp] -[no_lambdas_local_func] - -This code is somewhat less verbose than the previous example (about 30% less lines of code) but the contract code is hard to ready. - -Other libraries could also be used to program the contract functions without C++11 lambda functions (Boost.Lambda, Boost.Fusion, etc.) but like the techniques shown above, they will all result in contract code more verbose, or harder to read and maintain than the contract code programmed using C++11 lambda functions. -Therefore, authors think this library is most useful when used together with C++11 lambda functions. - -[endsect] - -[endsect] - - diff --git a/doc/full_table_of_contents.qbk b/doc/full_table_of_contents.qbk new file mode 100644 index 0000000..36319f9 --- /dev/null +++ b/doc/full_table_of_contents.qbk @@ -0,0 +1,69 @@ + +[section Full Table of Contents] + +[pre +__Introduction__ +__Full_Table_of_Contents__ +__Getting_Started__ + __This_Documentation__ + __Compilers_and_Platforms__ + __Code_Organization__ + __Install_and_Compile__ +__Contract_Programming_Overview__ + __Assertions__ + __Benefits_and_Costs__ + __Function_Calls__ + __Public_Function_Calls__ + __Constructor_Calls__ + __Destructor_Calls__ + __Constant_Correctness__ + __Specification_vs_Implementation__ + __On_Contract_Failure__ + __Feature_Summary__ +__Tutorial__ + __Non_Member_Functions__ + __Preconditions__ + __Postconditions__ + __Return_Value__ + __Old_Values__ + __Exception_Guarantees__ + __Class_Invariants__ + __Constructors__ + __Destructors__ + __Public_Functions__ + __Virtual_Public_Functions__ + __Public_Function_Overrides__ (Subcontracting) + __Base_Classes__ (Subcontracting) + __Static_Public_Functions__ +__Advanced_Topics__ + __Pure_Virtual_Public_Functions__ + __Optional_Return_Value__ + __Private_and_Protected_Functions__ + __Friend_Functions__ + __Function_Overloads__ + __Lambdas_Code_Blocks_Loops_Etc__ + __Implementation_Checks__ + __Old_Values_at_Body__ + __Named_Overrides__ + __Access_Specifiers__ + __Throw_on_Failure__ +__Extra_Topics__ + __Old_Value_Requirements__ (Templates) + __Assertion_Requirements__ (Templates) + __Volatile_Public_Functions__ + __Move_Operations__ + __Unions__ + __Disable_Contract_Checking__ + __Disable_Contract_Compilation__ (Macro Interface) + __Separate_Body_Implementation__ + __No_Lambda_Functions__ (No C++11) + __No_Macros__ (No C++11) +__Reference__ +__Examples__ +__Release_Notes__ +__Bibliography__ +__Acknowledgments__ +] + +[endsect] + diff --git a/doc/getting_started.qbk b/doc/getting_started.qbk index 78de642..3a8e2bc 100644 --- a/doc/getting_started.qbk +++ b/doc/getting_started.qbk @@ -19,6 +19,7 @@ These mark sections of the code that are automatically extracted from the source *Rationale:* This allows to make sure that most of the example code presented in this documentation is always up-to-date, builds and runs with the latest implementation of the library. ] +Also the purpose of these examples is to illustrate how to use this library and not to represent real product code. Some footnotes are marked by the word "*Rationale*". These explain reasons behind decisions made during the design and implementation of this library. @@ -79,7 +80,7 @@ Names starting with `BOOST_CONTRACT_ERROR...` are used by this library to report [endsect] -[section Installation and Compilation] +[section Install and Compile] Let [^['lib-root]] be the directory under which this library source files have been installed. Let [^['boost-root]] be the directory under which Boost source code has been installed and compiled following Boost's documentation (if pre-compiled Boost distributions are used instead, the [^['lib-boost]\/include] and [^['lib-boost]\/stage\/lib] directories below might be replaced by =/usr/include= and =/usr/lib= or similar directories depending on the specific Boost distribution, OS, etc.). diff --git a/doc/main.qbk b/doc/main.qbk index 185f7dd..c79fd44 100644 --- a/doc/main.qbk +++ b/doc/main.qbk @@ -13,7 +13,13 @@ ] [def __Introduction__ [link boost_contract.introduction Introduction]] +[def __Full_Table_of_Contents__ [link boost_contract.full_table_of_contents Full Table of Contents]] + [def __Getting_Started__ [link boost_contract.getting_started Getting Started]] +[def __This_Documentation__ [link boost_contract.getting_started.this_documentation This Documentation]] +[def __Compilers_and_Platforms__ [link boost_contract.getting_started.compilers_and_platforms Compilers and Platforms]] +[def __Code_Organization__ [link boost_contract.getting_started.code_organization Code Organization]] +[def __Install_and_Compile__ [link boost_contract.getting_started.install_and_compile Install and Compile]] [def __Contract_Programming_Overview__ [link boost_contract.contract_programming_overview Contract Programming Overview]] [def __Assertions__ [link boost_contract.contract_programming_overview.assertions Assertions]] @@ -24,6 +30,8 @@ [def __Destructor_Calls__ [link boost_contract.contract_programming_overview.destructor_calls Destructor Calls]] [def __Constant_Correctness__ [link boost_contract.contract_programming_overview.constant_correctness Constant-Correctness]] [def __Specification_vs_Implementation__ [link boost_contract.contract_programming_overview.specification_vs__implementation Specification vs. Implementation]] +[def __On_Contract_Failure__ [link boost_contract.contract_programming_overview.on_contract_failure On Contract Failure]] +[def __Feature_Summary__ [link boost_contract.contract_programming_overview.features_summary Feature Summary]] [def __Tutorial__ [link boost_contract.tutorial Tutorial]] [def __Non_Member_Functions__ [link boost_contract.tutorial.non_member_functions Non-Member Functions]] @@ -33,7 +41,6 @@ [def __Old_Values__ [link boost_contract.tutorial.old_values Old Values]] [def __Exception_Guarantees__ [link boost_contract.tutorial.exception_guarantees Exception Guarantees]] [def __Class_Invariants__ [link boost_contract.tutorial.class_invariants Class Invariants]] -[def __Static_Class_Invariants__ [link boost_contract.tutorial.class_invariants.static_class_invariants Static Class Invariants]] [def __Constructors__ [link boost_contract.tutorial.constructors Constructors]] [def __Destructors__ [link boost_contract.tutorial.destructors Destructors]] [def __Public_Functions__ [link boost_contract.tutorial.public_functions Public Functions]] @@ -44,24 +51,31 @@ [def __Advanced_Topics__ [link boost_contract.advanced_topics Advanced Topics]] [def __Pure_Virtual_Public_Functions__ [link boost_contract.advanced_topics.pure_virtual_public_functions Pure Virtual Public Functions]] -[def __Private_and_Protected_Functions__ [link boost_contract.tutorial.private_and_protected_functions Private and Protected Functions]] -[def __Old_Values_at_Body__ [link boost_contract.advanced_topics.old_values_at_body Old Values at Body]] [def __Optional_Return_Value__ [link boost_contract.advanced_topics.optional_return_value Optional Return Value]] -[def __Overloaded_Functions__ [link boost_contract.advanced_topics.overloaded_functions Overloaded Functions]] +[def __Private_and_Protected_Functions__ [link boost_contract.advanced_topics.private_and_protected_functions Private and Protected Functions]] +[def __Friend_Functions__ [link boost_contract.advanced_topics.friend_functions Friend Functions]] +[def __Function_Overloads__ [link boost_contract.advanced_topics.function_overloads Function Overloads]] +[def __Lambdas_Code_Blocks_Loops_Etc__ [link boost_contract.advanced_topics.lambdas__code_blocks__loops__etc_ Lambdas, Code Blocks, Loops, Etc.]] +[def __Implementation_Checks__ [link boost_contract.advanced_topics.implementation_checks Implementation Checks]] +[def __Old_Values_at_Body__ [link boost_contract.advanced_topics.old_values_at_body Old Values at Body]] [def __Named_Overrides__ [link boost_contract.advanced_topics.named_overrides Named Overrides]] -[def __Unions__ [link boost_contract.advanced_topics.unions Unions]] -[def __Volatile_Class_Invariants__ [link boost_contract.advanced_topics.volatile_class_invariants Volatile Class Invariants]] -[def __Old_Value_Requirements__ [link boost_contract.advanced_topics.old_value_requirements Old Value Requirements]] [def __Access_Specifiers__ [link boost_contract.advanced_topics.access_specifiers Access Specifiers]] -[def __Separate_Body_Implementation__ [link boost_contract.advanced_topics.separate_body_implementation Separate Body Implementation]] [def __Throw_on_Failure__ [link boost_contract.advanced_topics.throw_on_failure Throw on Failure]] -[def __Disable_Contract_Checking__ [link boost_contract.advanced_topics.disable_contract_checking Disable Contract Checking]] -[def __No_Macros__ [link boost_contract.advanced_topics.no_macros__no_c__11_ No Macros]] -[def __No_Lambda_Functions__ [link boost_contract.advanced_topics.no_lambda_functions__no_c__11_ No Lambda Functions]] + +[def __Extra_Topics__ [link boost_contract.extra_topics Extra Topics]] +[def __Old_Value_Requirements__ [link boost_contract.extra_topics.old_value_requirements__templates_ Old Value Requirements]] +[def __Assertion_Requirements__ [link boost_contract.extra_topics.assertion_requirements__templates_ Assertion Requirements]] +[def __Volatile_Public_Functions__ [link boost_contract.extra_topics.volatile_public_functions Volatile Public Functions]] +[def __Move_Operations__ [link boost_contract.extra_topics.move_operations Move Operations]] +[def __Unions__ [link boost_contract.extra_topics.unions Unions]] +[def __Disable_Contract_Checking__ [link boost_contract.extra_topics.disable_contract_checking Disable Contract Checking]] +[def __Disable_Contract_Compilation__ [link boost_contract.extra_topics.disable_contract_compilation__macro_interface_ Disable Contract Compilation]] +[def __Separate_Body_Implementation__ [link boost_contract.extra_topics.separate_body_implementation Separate Body Implementation]] +[def __No_Lambda_Functions__ [link boost_contract.extra_topics.no_lambda_functions__no_c__11_ No Lambda Functions]] +[def __No_Macros__ [link boost_contract.extra_topics.no_macros__no_c__11_ No Macros]] [def __Reference__ [link boost_contract.reference Reference]] [def __Examples__ [link boost_contract.examples Examples]] -[def __Annexes__ [link boost_contract.annexes Annexes]] [def __Release_Notes__ [link boost_contract.release_notes Release Notes]] [def __Bibliography__ [link boost_contract.bibliography Bibliography]] [def __Acknowledgments__ [link boost_contract.acknowledgments Acknowledgments]] @@ -87,6 +101,7 @@ [def __N1962__ [link N1962_anchor \[N1962\]]] [def __N2081__ [link N2081_anchor \[N2081\]]] [def __N2914__ [link N2914_anchor \[N2914\]]] +[def __N3613__ [link N3613_anchor \[N3613\]]] [def __SPARKAda__ [link SPARKAda_anchor \[SPARKAda\]]] [def __SpecSharp__ [link SpecSharp_anchor \[SpecSharp\]]] [def __Stroustrup94__ [link Stroustrup94_anchor \[Stroustrup94\]]] @@ -114,11 +129,12 @@ However, the authors have not had time yet to add this library to a Boost releas This library source is hosted at [@https://github.com/lcaminiti/boost-contract]. [include introduction.qbk] +[include full_table_of_contents.qbk] [include getting_started.qbk] [include contract_programming_overview.qbk] [include tutorial.qbk] [include advanced_topics.qbk] -[include extras.qbk] +[include extra_topics.qbk] [xinclude reference.xml] [include examples.qbk] [include release_notes.qbk] diff --git a/doc/tutorial.qbk b/doc/tutorial.qbk index d5cb242..3e061e0 100644 --- a/doc/tutorial.qbk +++ b/doc/tutorial.qbk @@ -8,13 +8,13 @@ This section illustrates basic uses of this library. -[section Non-Member Functions (Lambdas, Code Blocks, Etc.)] +[section Non-Member Functions] Contracts for non-member functions are programmed using [funcref boost::contract::function]. -For example (see also [@../../example/features/function.cpp =function.cpp=]): +For example (see also [@../../example/features/non_member.cpp =non_member.cpp=]): -[import ../example/features/function.cpp] -[function] +[import ../example/features/non_member.cpp] +[non_member] All necessary header files of this library are included by `#include `. Alternatively, programmers can selectively include only the header files they actually need among =boost/contract/*.hpp= (see __Getting_Started__). @@ -50,18 +50,6 @@ This ensures that non-member function contracts are correctly checked at run-tim A non-member function can avoid calling [funcref boost::contract::function] for efficiency but only when it has no preconditions, no postconditions, and no exception guarantees. ] -Similarly, contracts for lambda functions are also programmed using [funcref boost::contract::function]. -For example (see also [@../../example/features/lambda_function.cpp =lambda_function.cpp=]): - -[import ../example/features/lambda_function.cpp] -[lambda_function] - -Furthermore, [funcref boost::contract::function] can also be used to program contracts of code blocks within the implementation of a function (including code blocks defining `for`-loops, etc.). -For example (see also [@../../example/features/code_block.cpp =code_block.cpp=]): - -[import ../example/features/code_block.cpp] -[code_block] - [endsect] [section Preconditions] diff --git a/example/Jamfile.v2 b/example/Jamfile.v2 index 69b6b77..c6c9eba 100644 --- a/example/Jamfile.v2 +++ b/example/Jamfile.v2 @@ -11,8 +11,9 @@ test-suite features : [ subdir-run features : introduction ] [ subdir-run features : introduction_comments ] - [ subdir-run features : function ] - [ subdir-run features : lambda_function ] + [ subdir-run features : non_member ] + [ subdir-run features : lambda ] + [ subdir-run features : loop ] [ subdir-run features : code_block ] [ subdir-run features : public ] [ subdir-run features : base_types ] @@ -22,8 +23,11 @@ test-suite features : [ subdir-run features : private_protected_virtual_multi ] [ subdir-run features : check ] + [ subdir-run features : friend ] + [ subdir-run features : friend_invariant ] [ subdir-run features : old ] [ subdir-run features : optional_result ] + [ subdir-run features : optional_result_virtual ] [ subdir-run features : pure_virtual_public ] [ subdir-run features : overload ] [ subdir-run features : named_override ] @@ -39,8 +43,8 @@ test-suite features : [ subdir-run features : throw_on_failure ] [ subdir-run features : ifdef ] [ subdir-run features : ifdef_macro ] - [ subdir-run features : base_types_no_macros ] - [ subdir-run features : old_no_macros ] + [ subdir-run features : base_types_no_macro ] + [ subdir-run features : old_no_macro ] [ subdir-run features : no_lambdas ] [ subdir-run features : no_lambdas_local_func ] ; diff --git a/example/features/access.cpp b/example/features/access.cpp index d4b3ac0..618f3ec 100644 --- a/example/features/access.cpp +++ b/example/features/access.cpp @@ -53,7 +53,7 @@ private: typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types; // ...private bases. #undef BASES - BOOST_CONTRACT_OVERRIDE(push_back) // ..private overrides. + BOOST_CONTRACT_OVERRIDE(push_back) // ...private overrides. void invariant() const { // ...private invariants. BOOST_CONTRACT_ASSERT(size() <= capacity()); diff --git a/example/features/base_types_no_macros.cpp b/example/features/base_types_no_macro.cpp similarity index 99% rename from example/features/base_types_no_macros.cpp rename to example/features/base_types_no_macro.cpp index a55ef9c..1a79044 100644 --- a/example/features/base_types_no_macros.cpp +++ b/example/features/base_types_no_macro.cpp @@ -112,7 +112,7 @@ private: std::vector vect_; }; -//[base_types_no_macros +//[base_types_no_macro #include class chars : diff --git a/example/features/call_if_cxx14.cpp b/example/features/call_if_cxx14.cpp index 45bb129..98cf346 100644 --- a/example/features/call_if_cxx14.cpp +++ b/example/features/call_if_cxx14.cpp @@ -40,7 +40,7 @@ struct is_input_iterator : std::is_same< //[call_if_cxx14 template void myadvance(Iter& i, Dist n) { - Iter *p = &i; // So captures change actual pointed iterator value. + Iter* p = &i; // So captures change actual pointed iterator value. boost::contract::call_if >( std::bind([] (auto p, auto n) { // C++14 generic lambda. *p += n; diff --git a/example/features/check.cpp b/example/features/check.cpp index 7e62a5b..251d51c 100644 --- a/example/features/check.cpp +++ b/example/features/check.cpp @@ -5,7 +5,6 @@ // See: http://www.boost.org/doc/libs/release/libs/contract/doc/html/index.html #include -#include int gcd(int const a, int const b) { int result; @@ -20,32 +19,28 @@ int gcd(int const a, int const b) { }) ; - // Function body follows... - - //[check_class int x = a, y = b; - boost::contract::check c1 = [&] { // Body checks with functor. - BOOST_CONTRACT_ASSERT(x == a); - BOOST_CONTRACT_ASSERT(y == b); - }; - //] - - //[check_macro while(x != y) { - BOOST_CONTRACT_CHECK(x > 0); // Body checks with macros (preferred). - BOOST_CONTRACT_CHECK(y > 0); - if(x > y) x = x - y; else y = y - x; } - //] - return result = x; } int main() { - assert(gcd(12, 28) == 4); - assert(gcd(4, 14) == 2); + //[check_class + boost::contract::check c = [&] { // Implementation checks via functor. + BOOST_CONTRACT_ASSERT(gcd(12, 28) == 4); + BOOST_CONTRACT_ASSERT(gcd(4, 14) == 2); + }; + //] + + //[check_macro + // Implementation checks via macro (preferred). + BOOST_CONTRACT_CHECK(gcd(12, 28) == 4); + BOOST_CONTRACT_CHECK(gcd(4, 14) == 2); + //] + return 0; } diff --git a/example/features/code_block.cpp b/example/features/code_block.cpp index 4cef34f..63f250a 100644 --- a/example/features/code_block.cpp +++ b/example/features/code_block.cpp @@ -12,7 +12,8 @@ int main() { int total = 10; //[code_block - { // Contract for a code block (also for-loop, while-loop, etc.). + { + // Contract for a code block. boost::contract::old_ptr old_total = BOOST_CONTRACT_OLD(total); boost::contract::check c = boost::contract::function() .precondition([&] { @@ -23,7 +24,7 @@ int main() { }) ; - total += v[0] + v[1] + v[2]; // Body. + total += v[0] + v[1] + v[2]; // Code block body. } //] diff --git a/example/features/friend.cpp b/example/features/friend.cpp new file mode 100644 index 0000000..99415f3 --- /dev/null +++ b/example/features/friend.cpp @@ -0,0 +1,62 @@ + +#include +#include +#include + +//[friend_byte +class bytes; + +class byte { + friend bool operator==(bytes const& left, byte const& right); + +private: + char value_; + + /* ... */ +//] + +public: + // Could program invariants and contracts for following too. + explicit byte(char value) : value_(value) {} + bool empty() const { return value_ == '\0'; } +}; + +//[friend_bytes +class bytes { + // Friend functions are not member functions... + friend bool operator==(bytes const& left, byte const& right) { + // ...so check contracts via `function` (which won't check invariants). + boost::contract::check c = boost::contract::function() + .precondition([&] { + BOOST_CONTRACT_ASSERT(!left.empty()); + BOOST_CONTRACT_ASSERT(!right.empty()); + }) + ; + + for(char const* x = left.values_.c_str(); *x != '\0'; ++x) { + if(*x != right.value_) return false; + } + return true; + } + +private: + std::string values_; + + /* ... */ +//] + +public: + // Could program invariants and contracts for following too. + explicit bytes(std::string const& values) : values_(values) {} + bool empty() const { return values_ == ""; } +}; + +int main() { + bytes p("aaa"); + byte a('a'); + assert(p == a); + bytes q("aba"); + assert(!(q == a)); // No operator!=. + return 0; +} + diff --git a/example/features/friend_invariant.cpp b/example/features/friend_invariant.cpp new file mode 100644 index 0000000..530ec2d --- /dev/null +++ b/example/features/friend_invariant.cpp @@ -0,0 +1,54 @@ + +#include +#include + +//[friend_invariant +template +class positive { +public: + void invariant() const { + BOOST_CONTRACT_ASSERT(value() > 0); + } + + // Can be considered an extension of enclosing class' public interface... + friend void swap(positive& object, T& value) { + boost::contract::old_ptr old_object_value = + BOOST_CONTRACT_OLDOF(object.value()); + boost::contract::old_ptr old_value = BOOST_CONTRACT_OLDOF(value); + // ...so it can be made to check invariants via `public_function`. + boost::contract::check c = boost::contract::public_function(&object) + .precondition([&] { + BOOST_CONTRACT_ASSERT(value > 0); + }) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(object.value() == *old_value); + BOOST_CONTRACT_ASSERT(value == *old_object_value); + }) + ; + + T saved = object.value_; + object.value_ = value; + value = saved; + } + +private: + T value_; + + /* ... */ +//] + +public: + // Could program contracts for following too. + explicit positive(T const& value) : value_(value) {} + T value() const { return value_; } +}; + +int main() { + positive i(123); + int x = 456; + swap(i, x); + assert(i.value() == 456); + assert(x == 123); + return 0; +} + diff --git a/example/features/ifdef.cpp b/example/features/ifdef.cpp index 4315685..c6244b0 100644 --- a/example/features/ifdef.cpp +++ b/example/features/ifdef.cpp @@ -10,6 +10,7 @@ //[ifdef_function // Use #ifdef to selectively disable contract compilation. +#include #ifndef BOOST_CONTRACT_NO_ALL #include #endif diff --git a/example/features/ifdef_macro.cpp b/example/features/ifdef_macro.cpp index f76d127..6829d33 100644 --- a/example/features/ifdef_macro.cpp +++ b/example/features/ifdef_macro.cpp @@ -31,7 +31,7 @@ int inc(int& x) { template class pushable { - friend class boost::contract::access; // OK if this always left in code. + friend class boost::contract::access; // Almost no overhead, always in code. BOOST_CONTRACT_INVARIANT({ BOOST_CONTRACT_ASSERT(capacity() <= max_size()); @@ -40,7 +40,7 @@ class pushable { public: virtual void push_back( T const& x, - boost::contract::virtual_* v = 0 // OK if this always left in code. + boost::contract::virtual_* v = 0 // Almost no overhead, always in code. ) = 0; protected: @@ -66,11 +66,11 @@ void pushable::push_back(T const& x, boost::contract::virtual_* v) { class integers #define BASES public pushable : - // OK if following extra base class always left in code. + // Almost no overhead for this extra base, always in code. private boost::contract::constructor_precondition, BASES { - // OK if followings always left in code. + // Almost no overhead for followings, always in code. friend class boost::contract::access; typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types; #undef BASES @@ -122,7 +122,7 @@ public: } private: - BOOST_CONTRACT_OVERRIDE(push_back) // OK if always left in code. + BOOST_CONTRACT_OVERRIDE(push_back) // About no overhead, always in code. /* ... */ //] diff --git a/example/features/lambda_function.cpp b/example/features/lambda.cpp similarity index 92% rename from example/features/lambda_function.cpp rename to example/features/lambda.cpp index 7167f0c..a6b5137 100644 --- a/example/features/lambda_function.cpp +++ b/example/features/lambda.cpp @@ -10,11 +10,11 @@ int main() { v.push_back(2); v.push_back(3); - //[lambda_function + //[lambda int total = 0; std::for_each(v.cbegin(), v.cend(), - // Contract for a lambda function. [&total] (int const x) { + // Contract for a lambda function. boost::contract::old_ptr old_total = BOOST_CONTRACT_OLD(total); boost::contract::check c = boost::contract::function() .precondition([&] { diff --git a/example/features/loop.cpp b/example/features/loop.cpp new file mode 100644 index 0000000..723f8e0 --- /dev/null +++ b/example/features/loop.cpp @@ -0,0 +1,35 @@ + +#include +#include +#include +#include + +int main() { + std::vector v; + v.push_back(1); + v.push_back(2); + v.push_back(3); + + //[loop + int total = 0; + for(std::vector::const_iterator i = v.begin(); i != v.end(); ++i) { + // Contract for a for-loop (same for while- and all other loops). + boost::contract::old_ptr old_total = BOOST_CONTRACT_OLD(total); + boost::contract::check c = boost::contract::function() + .precondition([&] { + BOOST_CONTRACT_ASSERT( + total + *i <= std::numeric_limits::max()); + }) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(total == *old_total + *i); + }) + ; + + total += *i; // For-loop body. + } + //] + + assert(total == 6); + return 0; +} + diff --git a/example/features/move.cpp b/example/features/move.cpp index 82c96bb..5e0f66d 100644 --- a/example/features/move.cpp +++ b/example/features/move.cpp @@ -17,8 +17,59 @@ public: if(!moved()) { // Do not check (some) invariants for moved-from objects. BOOST_CONTRACT_ASSERT(index() < size()); } + // More invariants here (that must hold also for moved-from objects). + } + + // Move constructor. + /* implicit */ circular_buffer(circular_buffer&& other) : + boost::contract::constructor_precondition([&] { + BOOST_CONTRACT_ASSERT(!other.moved()); + }) + { + boost::contract::check c = boost::contract::constructor(this) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(!moved()); + BOOST_CONTRACT_ASSERT(other.moved()); + }) + ; + + move(std::forward(other)); + } + + // Move assignment. + circular_buffer& operator=(circular_buffer&& other) { + // Moved-from can be (move) assigned (so no pre `!moved()` here). + boost::contract::check c = boost::contract::public_function(this) + .precondition([&] { + BOOST_CONTRACT_ASSERT(!other.moved()); + }) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(!moved()); + BOOST_CONTRACT_ASSERT(other.moved()); + }) + ; + + return move(std::forward(other)); + } + + ~circular_buffer() { + // Moved-from can always be destroyed (in fact no preconditions). + boost::contract::check c = boost::contract::destructor(this); + } + + bool moved() const { + boost::contract::check c = boost::contract::public_function(this); + return moved_; } +private: + + bool moved_; + + /* ... */ +//] + +public: explicit circular_buffer(std::vector const& data, unsigned start = 0) : boost::contract::constructor_precondition([&] { @@ -35,11 +86,6 @@ public: ; } - ~circular_buffer() { - // Moved-from can always be destroyed (so no pre `!moved()` here). - boost::contract::check c = boost::contract::destructor(this); - } - // Copy constructor. /* implicit */ circular_buffer(circular_buffer const& other) : boost::contract::constructor_precondition([&] { @@ -70,38 +116,6 @@ public: return copy(other); } - // Move constructor. - /* implicit */ circular_buffer(circular_buffer&& other) : - boost::contract::constructor_precondition([&] { - BOOST_CONTRACT_ASSERT(!other.moved()); - }) - { - boost::contract::check c = boost::contract::constructor(this) - .postcondition([&] { - BOOST_CONTRACT_ASSERT(!moved()); - BOOST_CONTRACT_ASSERT(other.moved()); - }) - ; - - move(std::forward(other)); - } - - // Move assignment. - circular_buffer& operator=(circular_buffer&& other) { - // Moved-from can be (move) assigned (so no pre `!moved()` here). - boost::contract::check c = boost::contract::public_function(this) - .precondition([&] { - BOOST_CONTRACT_ASSERT(!other.moved()); - }) - .postcondition([&] { - BOOST_CONTRACT_ASSERT(!moved()); - BOOST_CONTRACT_ASSERT(other.moved()); - }) - ; - - return move(std::forward(other)); - } - char read() { boost::contract::check c = boost::contract::public_function(this) .precondition([&] { @@ -114,11 +128,6 @@ public: return data_.at(i); } - bool moved() const { - boost::contract::check c = boost::contract::public_function(this); - return moved_; - } - private: circular_buffer& copy(circular_buffer const& other) { data_ = other.data_; @@ -137,10 +146,6 @@ private: std::vector data_; unsigned index_; - bool moved_; - - /* ... */ -//] public: unsigned index() const { diff --git a/example/features/named_override.cpp b/example/features/named_override.cpp index 806c45c..4c15c65 100644 --- a/example/features/named_override.cpp +++ b/example/features/named_override.cpp @@ -20,8 +20,7 @@ template void generic_unary_pack::_1(T const& value, boost::contract::virtual_* v) { boost::contract::check c = boost::contract::public_function(v, this) .precondition([&] { - // Derived concrete classes will enforce preconditions. - BOOST_CONTRACT_ASSERT(false); + BOOST_CONTRACT_ASSERT(false); // Defer preconditions to overrides. }) ; assert(false); @@ -54,7 +53,7 @@ public: #undef BASES // BOOST_CONTRACT_OVERRIDE(_1) would generate reserved symbol `override__1`. - BOOST_CONTRACT_NAMED_OVERRIDE(override1, _1) + BOOST_CONTRACT_NAMED_OVERRIDE(override1, _1) // Generate `override1`. virtual void _1(T const& value, boost::contract::virtual_* v = 0) /* override */ { diff --git a/example/features/function.cpp b/example/features/non_member.cpp similarity index 98% rename from example/features/function.cpp rename to example/features/non_member.cpp index 92268b2..2444e07 100644 --- a/example/features/function.cpp +++ b/example/features/non_member.cpp @@ -7,7 +7,7 @@ #include #include -//[function +//[non_member #include // Contract for a non-member function. diff --git a/example/features/old.cpp b/example/features/old.cpp index c37e3e2..bed555b 100644 --- a/example/features/old.cpp +++ b/example/features/old.cpp @@ -6,11 +6,10 @@ #include #include -#include #include //[old -char replace(std::string& s, std::size_t index, char x) { +char replace(std::string& s, unsigned index, char x) { char result; boost::contract::old_ptr old_y; // But old value copied later... boost::contract::check c = boost::contract::function() @@ -18,7 +17,7 @@ char replace(std::string& s, std::size_t index, char x) { BOOST_CONTRACT_ASSERT(index < s.size()); }) .old([&] { // ...after preconditions (and invariants) checked. - old_y = BOOST_CONTRACT_OLD(s[index]); + old_y = BOOST_CONTRACT_OLD(s[index]); // Checked `index` in range. }) .postcondition([&] { BOOST_CONTRACT_ASSERT(s[index] == x); diff --git a/example/features/old_if_copyable.cpp b/example/features/old_if_copyable.cpp index 5c3c8f8..f46043d 100644 --- a/example/features/old_if_copyable.cpp +++ b/example/features/old_if_copyable.cpp @@ -36,15 +36,28 @@ private: }; // Specialize `boost::is_copy_constructible` trait (not needed on C++11): +#include +#ifdef BOOST_NO_CXX11_DELETED_FUNCTIONS + +//[old_if_copyable_specialization +#include + +namespace boost { + template<> + struct is_copy_constructible : false_type {}; +} +//] + +#endif int main() { - n j, k; + n j, k; // Non copyable (no compiler error but no old-value checks). j.value = 1; k.value = 2; accumulate(j, k); assert(j.value == 3); - int i = 1; + int i = 1; // Copyable (check old values). accumulate(i, 2); assert(i == 3); diff --git a/example/features/old_no_macros.cpp b/example/features/old_no_macro.cpp similarity index 98% rename from example/features/old_no_macros.cpp rename to example/features/old_no_macro.cpp index 7099004..dd32679 100644 --- a/example/features/old_no_macros.cpp +++ b/example/features/old_no_macro.cpp @@ -8,7 +8,7 @@ #include #include -//[old_no_macros +//[old_no_macro template class vector { public: diff --git a/example/features/optional_result.cpp b/example/features/optional_result.cpp index c8f4e0e..e454894 100644 --- a/example/features/optional_result.cpp +++ b/example/features/optional_result.cpp @@ -6,37 +6,36 @@ #include #include +#include #include //[optional_result -struct surface { - int area; - int perimeter; - - // No default constructor. - surface(int area, int perimeter) : area(area), perimeter(perimeter) {} -}; - -surface squared_surface(int edge) { - boost::optional result; // No default constructor so use optional. +template +T& get(std::vector& vect) { + boost::optional result; // Result not initialized here... boost::contract::check c = boost::contract::function() .precondition([&] { - BOOST_CONTRACT_ASSERT(edge > 0); + BOOST_CONTRACT_ASSERT(Index < vect.size()); }) .postcondition([&] { - BOOST_CONTRACT_ASSERT(result->area == edge * edge); - BOOST_CONTRACT_ASSERT(result->perimeter == edge * 4); + BOOST_CONTRACT_ASSERT(*result == vect[Index]); }) ; - - return *(result = surface(edge * edge, edge * 4)); + + // Function body (executed after preconditions checked). + return *(result = vect[Index]); // ...result initialized here instead. } //] int main() { - surface s = squared_surface(10); - assert(s.area == 100); - assert(s.perimeter == 40); + std::vector v; + v.push_back(123); + v.push_back(456); + v.push_back(789); + int& x = get<1>(v); + assert(x == 456); + x = -456; + assert(v[1] == -456); return 0; } diff --git a/example/features/optional_result_virtual.cpp b/example/features/optional_result_virtual.cpp new file mode 100644 index 0000000..7fd4af5 --- /dev/null +++ b/example/features/optional_result_virtual.cpp @@ -0,0 +1,88 @@ + +// Copyright (C) 2008-2016 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 +#include +#include +#include + +template +class accessible { +public: + virtual T& at(unsigned index, boost::contract::virtual_* v = 0) = 0; + + // Could program class invariants and contracts for following too. + virtual T const& operator[](unsigned index) const = 0; + virtual unsigned size() const = 0; +}; + +//[optional_result_virtual +template +T& accessible::at(unsigned index, boost::contract::virtual_* v) { + boost::optional result; + // Pass `result` right after `v`... + boost::contract::check c = boost::contract::public_function(v, result, this) + .precondition([&] { + BOOST_CONTRACT_ASSERT(index < size()); + }) + // ...plus postconditions take `result` as a parameter (not capture). + .postcondition([&] (boost::optional const& result) { + BOOST_CONTRACT_ASSERT(*result == operator[](index)); + }) + ; + + assert(false); + return *result; +} +//] + +template +class vector + #define BASES public accessible + : BASES +{ +public: + typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types; + #undef BASES + + T& at(unsigned index, boost::contract::virtual_* v = 0) /* override */ { + boost::optional result; + // Pass `result` right after `v`... + boost::contract::check c = boost::contract::public_function< + override_at>(v, result, &vector::at, this, index) + // ...plus postconditions take `result` as parameter (not capture). + .postcondition([&] (boost::optional const& result) { + if(index == 0) BOOST_CONTRACT_ASSERT(*result == front()); + }) + ; + + return *(result = vect_[index]); + } + + // Could program class invariants and contracts for following too. + T const& operator[](unsigned index) const { return vect_[index]; } + unsigned size() const { return vect_.size(); } + T const& front() const { return vect_.front(); } + void push_back(T const& value) { vect_.push_back(value); } + + BOOST_CONTRACT_OVERRIDE(at) + +private: + std::vector vect_; +}; + +int main() { + vector v; + v.push_back(123); + v.push_back(456); + v.push_back(789); + int& x = v.at(1); + assert(x == 456); + x = -456; + assert(v.at(1) == -456); + return 0; +} + diff --git a/example/features/overload.cpp b/example/features/overload.cpp index 75caa6f..ae276e4 100644 --- a/example/features/overload.cpp +++ b/example/features/overload.cpp @@ -83,15 +83,18 @@ public: typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types; #undef BASES - BOOST_CONTRACT_OVERRIDES(str) // Used only once for all `str` overloads. + BOOST_CONTRACT_OVERRIDES(str) // Invoked only once for all `str` overloads. std::string str(boost::contract::virtual_* v = 0) const /* override */ { std::string result; boost::contract::check c = boost::contract::public_function< - override_str - // Note the use of `static_cast` (and same in other overloads below). - >(v, result, static_cast(&string_lines::str), this); + override_str>( + v, result, + // `static_cast` resolves overloaded function pointer ambiguities. + static_cast(&string_lines::str), + this + ); return result = str_; } @@ -99,23 +102,31 @@ public: // Overload on (absence of) `const` qualifier. std::string& str(boost::contract::virtual_* v = 0) /* override */ { boost::contract::check c = boost::contract::public_function< - override_str - >(v, str_, static_cast(&string_lines::str), this); + override_str>( + v, str_, + // `static_cast` resolves overloaded function pointer ambiguities. + static_cast(&string_lines::str), + this + ); return str_; } - BOOST_CONTRACT_OVERRIDES(put) // Used only once for all `put` overloads. + BOOST_CONTRACT_OVERRIDES(put) // Invoked only once for all `put` overloads. void put(std::string const& x, boost::contract::virtual_* v = 0) /* override */ { boost::contract::old_ptr old_str = BOOST_CONTRACT_OLD(v, str()); boost::contract::check c = boost::contract::public_function< - override_put - >(v, static_cast(&string_lines::put), this, x) + override_put>( + v, + // `static_cast` resolves overloaded function pointer ambiguities. + static_cast(&string_lines::put), + this, x + ) .postcondition([&] { BOOST_CONTRACT_ASSERT(str() == *old_str + x + '\n'); }) @@ -129,9 +140,13 @@ public: boost::contract::old_ptr old_str = BOOST_CONTRACT_OLD(v, str()); boost::contract::check c = boost::contract::public_function< - override_put - >(v, static_cast(&string_lines::put), this, x) + override_put>( + v, + // `static_cast` resolves overloaded function pointer ambiguities. + static_cast(&string_lines::put), + this, x + ) .postcondition([&] { BOOST_CONTRACT_ASSERT(str() == *old_str + x + '\n'); }) @@ -146,9 +161,13 @@ public: boost::contract::old_ptr old_str = BOOST_CONTRACT_OLD(v, str()); boost::contract::check c = boost::contract::public_function< - override_put - >(v, static_cast(&string_lines::put), this, x, tab) + override_put>( + v, + // `static_cast` resolves overloaded function pointer ambiguities. + static_cast(&string_lines::put), + this, x, tab + ) .postcondition([&] { std::ostringstream s; s << x; diff --git a/example/features/private_protected.cpp b/example/features/private_protected.cpp index 7b79105..1f81800 100644 --- a/example/features/private_protected.cpp +++ b/example/features/private_protected.cpp @@ -10,26 +10,7 @@ //[private_protected class counter { - // Private and protected functions use `function()` like non-members. - -private: - int n_; - - void dec() { - boost::contract::old_ptr old_get = BOOST_CONTRACT_OLD(get()); - boost::contract::check c = boost::contract::function() - .precondition([&] { - BOOST_CONTRACT_ASSERT( - get() + 1 >= std::numeric_limits::min()); - }) - .postcondition([&] { - BOOST_CONTRACT_ASSERT(get() == *old_get - 1); - }) - ; - - set(get() - 1); - } - + // Private and protected functions use `function()` (like non-members). protected: virtual void set(int n, boost::contract::virtual_* = 0) { boost::contract::check c = boost::contract::function() @@ -44,6 +25,24 @@ protected: n_ = n; } +private: + void dec() { + boost::contract::old_ptr old_get = BOOST_CONTRACT_OLD(get()); + boost::contract::check c = boost::contract::function() + .precondition([&] { + BOOST_CONTRACT_ASSERT( + get() + 1 >= std::numeric_limits::min()); + }) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(get() == *old_get - 1); + }) + ; + + set(get() - 1); + } + + int n_; + /* ... */ //] diff --git a/example/features/private_protected_virtual.cpp b/example/features/private_protected_virtual.cpp index ed2acbd..fad9694 100644 --- a/example/features/private_protected_virtual.cpp +++ b/example/features/private_protected_virtual.cpp @@ -10,12 +10,23 @@ //[private_protected_virtual_counter class counter { - // Private and protected virtual functions declare extra `virtual_* = 0` - // parameter (otherwise they cannot be overridden). + // Virtual private and protected functions still declare extra + // `virtual_* = 0` parameter (otherwise they cannot be overridden). +protected: + virtual void set(int n, boost::contract::virtual_* = 0) { + boost::contract::check c = boost::contract::function() + .precondition([&] { + BOOST_CONTRACT_ASSERT(n <= 0); + }) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(get() == n); + }) + ; + + n_ = n; + } private: - int n_; - virtual void dec(boost::contract::virtual_* = 0) { boost::contract::old_ptr old_get = BOOST_CONTRACT_OLD(get()); boost::contract::check c = boost::contract::function() @@ -30,20 +41,8 @@ private: set(get() - 1); } - -protected: - virtual void set(int n, boost::contract::virtual_* = 0) { - boost::contract::check c = boost::contract::function() - .precondition([&] { - BOOST_CONTRACT_ASSERT(n <= 0); - }) - .postcondition([&] { - BOOST_CONTRACT_ASSERT(get() == n); - }) - ; - - n_ = n; - } + + int n_; /* ... */ //] @@ -80,9 +79,22 @@ public: typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types; #undef BASES - // Not overriding from public members so no `override_...`. + // Overriding from non-public members so no subcontracting, no override_... + + virtual void set(int n, boost::contract::virtual_* v = 0) /* override */ { + boost::contract::check c = boost::contract::public_function(v, this) + .precondition([&] { + BOOST_CONTRACT_ASSERT(n % 10 == 0); + }) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(get() == n); + }) + ; - virtual void dec(boost::contract::virtual_* v = 0) { + counter::set(n); + } + + virtual void dec(boost::contract::virtual_* v = 0) /* override */ { boost::contract::old_ptr old_get = BOOST_CONTRACT_OLD(v, get()); boost::contract::check c = boost::contract::public_function(v, this) .precondition([&] { @@ -97,19 +109,6 @@ public: set(get() - 10); } - virtual void set(int n, boost::contract::virtual_* v = 0) { - boost::contract::check c = boost::contract::public_function(v, this) - .precondition([&] { - BOOST_CONTRACT_ASSERT(n % 10 == 0); - }) - .postcondition([&] { - BOOST_CONTRACT_ASSERT(get() == n); - }) - ; - - counter::set(n); - } - /* ... */ //] diff --git a/example/features/private_protected_virtual_multi.cpp b/example/features/private_protected_virtual_multi.cpp index f633f8b..fa89272 100644 --- a/example/features/private_protected_virtual_multi.cpp +++ b/example/features/private_protected_virtual_multi.cpp @@ -22,29 +22,9 @@ int main() { return 0; } // Trivial program for MSVC. #include #include -//[private_protected_virtual_multi_counter class counter { - // Private and protected virtual functions declare extra `virtual_* = 0` - // parameter (otherwise they cannot be overridden). - -private: - int n_; - - virtual void dec(boost::contract::virtual_* = 0) { - boost::contract::old_ptr old_get = BOOST_CONTRACT_OLD(get()); - boost::contract::check c = boost::contract::function() - .precondition([&] { - BOOST_CONTRACT_ASSERT( - get() + 1 >= std::numeric_limits::min()); - }) - .postcondition([&] { - BOOST_CONTRACT_ASSERT(get() == *old_get - 1); - }) - ; - - set(get() - 1); - } - + // Virtual private and protected functions still declare extra + // `virtual_* = 0` parameter (otherwise they cannot be overridden). protected: virtual void set(int n, boost::contract::virtual_* = 0) { boost::contract::check c = boost::contract::function() @@ -59,8 +39,23 @@ protected: n_ = n; } - /* ... */ -//] +private: + virtual void dec(boost::contract::virtual_* = 0) { + boost::contract::old_ptr old_get = BOOST_CONTRACT_OLD(get()); + boost::contract::check c = boost::contract::function() + .precondition([&] { + BOOST_CONTRACT_ASSERT( + get() + 1 >= std::numeric_limits::min()); + }) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(get() == *old_get - 1); + }) + ; + + set(get() - 1); + } + + int n_; public: virtual int get(boost::contract::virtual_* v = 0) const { @@ -135,7 +130,7 @@ int countable::get(boost::contract::virtual_* v) const { //[private_protected_virtual_multi_counter10 class counter10 - #define BASES public countable, public counter + #define BASES public countable, public counter // Multiple inheritance. : BASES { public: @@ -144,7 +139,21 @@ public: // Overriding from public members from `countable` so use `override_...`. - virtual void dec(boost::contract::virtual_* v = 0) { + virtual void set(int n, boost::contract::virtual_* v = 0) /* override */ { + boost::contract::check c = boost::contract::public_function< + override_set>(v, &counter10::set, this, n) + .precondition([&] { + BOOST_CONTRACT_ASSERT(n % 10 == 0); + }) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(get() == n); + }) + ; + + counter::set(n); + } + + virtual void dec(boost::contract::virtual_* v = 0) /* override */ { boost::contract::old_ptr old_get = BOOST_CONTRACT_OLD(v, get()); boost::contract::check c = boost::contract::public_function< override_dec>(v, &counter10::dec, this) @@ -160,21 +169,7 @@ public: set(get() - 10); } - virtual void set(int n, boost::contract::virtual_* v = 0) { - boost::contract::check c = boost::contract::public_function< - override_set>(v, &counter10::set, this, n) - .precondition([&] { - BOOST_CONTRACT_ASSERT(n % 10 == 0); - }) - .postcondition([&] { - BOOST_CONTRACT_ASSERT(get() == n); - }) - ; - - counter::set(n); - } - - BOOST_CONTRACT_OVERRIDES(dec, set) + BOOST_CONTRACT_OVERRIDES(set, dec) /* ... */ //] diff --git a/example/features/pure_virtual_public.cpp b/example/features/pure_virtual_public.cpp index c14bca3..78f6dd8 100644 --- a/example/features/pure_virtual_public.cpp +++ b/example/features/pure_virtual_public.cpp @@ -5,103 +5,89 @@ // See: http://www.boost.org/doc/libs/release/libs/contract/doc/html/index.html #include -#include +#include #include //[pure_virtual_public_base -struct surface { - int area; - int perimeter; - - // No default constructor. - surface(int area, int perimeter) : area(area), perimeter(perimeter) {} -}; - -class shape { +template +class range { public: - virtual surface get_surface(boost::contract::virtual_* v = 0) const = 0; -}; + // Pure virtual function declaration (contract not here, below instead). + virtual Iterator begin(boost::contract::virtual_* v = 0) = 0; + + /* ... */ //] + // Could program class invariants and contracts for the following too. + virtual Iterator end() = 0; + virtual bool empty() const = 0; +}; + //[pure_virtual_public_impl -// Pure-virtual function definition (and contract) out-of-line (usual in C++). -surface shape::get_surface(boost::contract::virtual_* v) const { - boost::optional result; +// Pure virtual function default implementation (out-of-line in C++). +template +Iterator range::begin(boost::contract::virtual_* v) { + Iterator result; // Pass `result` right after `v`... boost::contract::check c = boost::contract::public_function(v, result, this) - // ...and postconditions take `result` as parameter (not capture). - .postcondition([&] (boost::optional const& result) { - BOOST_CONTRACT_ASSERT(result->area > 0); - BOOST_CONTRACT_ASSERT(result->perimeter > 0); + // ...plus postconditions take `result` as parameter (not capture). + .postcondition([&] (Iterator const& result) { + if(empty()) BOOST_CONTRACT_ASSERT(result == end()); }) ; - assert(false); // Pure function body (never executed by this library). - return *result; + assert(false); // Pure function body never executed by this library. + return result; } //] //[pure_virtual_public_derived -class square - #define BASES private boost::contract::constructor_precondition, \ - public shape +template +class vector + #define BASES public range::iterator> : BASES { public: typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types; #undef BASES + typedef typename std::vector::iterator iterator; - surface get_surface(boost::contract::virtual_* v = 0) const /* override */ { - boost::optional result; + iterator begin(boost::contract::virtual_* v = 0) /* override */ { + iterator result; + // Again, pass result right after `v`... boost::contract::check c = boost::contract::public_function< - override_get_surface>(v, result, &square::get_surface, this) - .postcondition([&] (boost::optional const& result) { - BOOST_CONTRACT_ASSERT(result->area == edge() * edge()); - BOOST_CONTRACT_ASSERT(result->perimeter == edge() * 4); + override_begin>(v, result, &vector::begin, this) + // ...plus postconditions take `result` as parameter (not capture). + .postcondition([&] (iterator const& result) { + if(!empty()) BOOST_CONTRACT_ASSERT(*result == front()); }) ; - return *(result = surface(edge() * edge(), edge() * 4)); + return result = vect_.begin(); } - BOOST_CONTRACT_OVERRIDE(get_surface) /* ... */ //] - - explicit square(int edge) : - boost::contract::constructor_precondition([&] { - BOOST_CONTRACT_ASSERT(edge > 0); - }), - edge_(edge) - { - // Check invariants. - boost::contract::check c = boost::contract::constructor(this); - } - ~square() { - // Check invariants. - boost::contract::check c = boost::contract::destructor(this); - } + // Could program class invariants and contracts for the following too. + iterator end() { return vect_.end(); } + bool empty() const { return vect_.empty(); } + T const& front() const { return vect_.front(); } + void push_back(T const& value) { vect_.push_back(value); } - int edge() const { - // Check invariants. - boost::contract::check c = boost::contract::public_function(this); - return edge_; - } - - void invarinat() const { - BOOST_CONTRACT_ASSERT(edge() > 0); - } + BOOST_CONTRACT_OVERRIDE(begin) private: - int edge_; + std::vector vect_; }; int main() { - square sq(10); - surface s = sq.get_surface(); - assert(s.area == 100); - assert(s.perimeter == 40); + vector v; + v.push_back(1); + v.push_back(2); + v.push_back(3); + range::iterator>& r = v; + assert(*(r.begin()) == 1); return 0; } diff --git a/example/features/throw_on_failure.cpp b/example/features/throw_on_failure.cpp index 1eb4fd5..74a91db 100644 --- a/example/features/throw_on_failure.cpp +++ b/example/features/throw_on_failure.cpp @@ -12,7 +12,7 @@ //[throw_on_failure_cstring struct too_large_error {}; -template +template class cstring #define BASES private boost::contract::constructor_precondition > @@ -39,7 +39,7 @@ public: ; size_ = std::strlen(chars); - for(std::size_t i = 0; i < size_; ++i) chars_[i] = chars[i]; + for(unsigned i = 0; i < size_; ++i) chars_[i] = chars[i]; chars_[size_] = '\0'; } @@ -47,8 +47,8 @@ public: // Check invariants. boost::contract::check c = boost::contract::destructor(this); } - - std::size_t size() const { + + unsigned size() const { // Check invariants. boost::contract::check c = boost::contract::public_function(this); return size_; @@ -62,23 +62,32 @@ public: private: char chars_[MaxSize + 1]; - std::size_t size_; + unsigned size_; }; //[throw_on_failure_handler int main() { - boost::contract::set_specification_failure( - [] (boost::contract::from context) { - if(context == boost::contract::from_destructor) { - // Ignore exception because destructors should never throw. - std::clog << "destructor contract failed (ignored)" << - std::endl; - } else throw; // Rethrow (assertion_failure, too_large_error, etc.). + boost::contract::set_precondition_failure( + boost::contract::set_postcondition_failure( + boost::contract::set_invariant_failure( + boost::contract::set_old_failure( + [] (boost::contract::from where) { + if(where == boost::contract::from_destructor) { + // Cannot throw from destructors in C++. + std::clog << "ignored destructor contract failure" << std::endl; + } else throw; // Re-throw (assertion_failure, user-defined, etc.). + } + )))); + boost::contract::set_except_failure( + [] (boost::contract::from where) { + // Already an active exception so can't throw another in C++. + std::clog << "ignored exception guarantee failure" << std::endl; } ); - boost::contract::set_check_failure( // Then do not use CHECK in destructors. + boost::contract::set_check_failure( [] { - throw; // Rethrow (assertion_failure, too_large_error, etc.). + // But now CHECK cannot be used within destructor implementations. + throw; // Re-throw (assertion_failure, user-defined, etc.). } ); diff --git a/example/features/union.cpp b/example/features/union.cpp index dacb47a..983a5a2 100644 --- a/example/features/union.cpp +++ b/example/features/union.cpp @@ -14,16 +14,17 @@ //[union union positive { - static void static_invariant() { +public: + static void static_invariant() { // Static class invariants. BOOST_CONTRACT_ASSERT(instances() >= 0); } - void invariant() const { + void invariant() const { // Class invariants. BOOST_CONTRACT_ASSERT(i_ > 0); BOOST_CONTRACT_ASSERT(d_ > 0); } - explicit positive(int x) { + explicit positive(int x) { // Contracts for a constructor. // Unions cannot have bases so ctor preconditions here. boost::contract::constructor_precondition pre([&] { BOOST_CONTRACT_ASSERT(x > 0); @@ -40,6 +41,41 @@ union positive { ++instances_; } + ~positive() { // Contracts for the destructor. + boost::contract::old_ptr old_instances = + BOOST_CONTRACT_OLD(instances()); + boost::contract::check c = boost::contract::destructor(this) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(instances() == *old_instances - 1); + }) + ; + + --instances_; + } + + void get(int& x) { // Contracts for a public function. + boost::contract::check c = boost::contract::public_function(this) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(x > 0); + }); + ; + + x = i_; + } + + static int instances() { // Contracts for a static public function. + boost::contract::check c = boost::contract::public_function(); + return instances_; + } + +private: + int i_; + double d_; + + /* ... */ +//] + +public: explicit positive(double x) { // Unions cannot have bases so ctor preconditions here. boost::contract::constructor_precondition pre([&] { @@ -56,28 +92,6 @@ union positive { d_ = x; ++instances_; } - - ~positive() { - boost::contract::old_ptr old_instances = - BOOST_CONTRACT_OLD(instances()); - boost::contract::check c = boost::contract::destructor(this) - .postcondition([&] { - BOOST_CONTRACT_ASSERT(instances() == *old_instances - 1); - }) - ; - - --instances_; - } - - void get(int& x) { - boost::contract::check c = boost::contract::public_function(this) - .postcondition([&] { - BOOST_CONTRACT_ASSERT(x > 0); - }); - ; - - x = i_; - } void get(double& x) { boost::contract::check c = boost::contract::public_function(this) @@ -89,17 +103,6 @@ union positive { x = d_; } - static int instances() { - boost::contract::check c = boost::contract::public_function(); - return instances_; - } - -private: - int i_; - double d_; - - /* ... */ -//] #ifndef BOOST_GCC // G++ does not support static union members yet. static int instances_; #endif diff --git a/example/features/volatile.cpp b/example/features/volatile.cpp index b4fdd4d..31c5826 100644 --- a/example/features/volatile.cpp +++ b/example/features/volatile.cpp @@ -21,19 +21,19 @@ public: boost::contract::check c = boost::contract::destructor(this); } - void m() { // Check const invariant (at entry and exit if no throw). + void m() { // Check const invariant (at entry and exit). boost::contract::check c = boost::contract::public_function(this); } - void c() const { // Check const invariant (at entry and exit if no throw). + void c() const { // Check const invariant (at entry and exit). boost::contract::check c = boost::contract::public_function(this); } - void v() volatile { // Check cv invariant (at entry and exit if no throw). + void v() volatile { // Check cv invariant (at entry and exit). boost::contract::check c = boost::contract::public_function(this); } - void cv() const volatile { // Check cv inv. (at entry and exit if no throw). + void cv() const volatile { // Check cv invariant (at entry and exit). boost::contract::check c = boost::contract::public_function(this); } }; diff --git a/include/boost/contract/call_if.hpp b/include/boost/contract/call_if.hpp index 19568c8..d73b860 100644 --- a/include/boost/contract/call_if.hpp +++ b/include/boost/contract/call_if.hpp @@ -47,12 +47,12 @@ used via its specializations. Usually this class template is instantiated only via the return value of @RefFunc{boost::contract::call_if} and @RefFunc{boost::contract::call_if_c}. @see @RefSect{advanced_topics, Advanced Topics} -@tparam Cond Static boolean condition selecting which functor call to compile +@tparam Pred Static boolean condition selecting which functor call to compile and execute. @tparam Then Type of functor to call when the static condition if true. @tparam ThenResult Return type of then-branch functor call. */ -template -call_if_statement call_if_c(Then f) { - return call_if_statement(f); +template +call_if_statement call_if_c(Then f) { + return call_if_statement(f); } /** @@ -390,20 +390,20 @@ meta-function. Make a call-if object with the specified then-branch functor. @see @RefSect{advanced_topics, Advanced Topics} @param f Then-branch nullary templated functor. The functor call @c f() is - compiled and executed if and only if @c Cond::value if @c true. The + compiled and executed if and only if @c Pred::value if @c true. The return type of other functor calls specified for this call-if statement (else-branches, else-if-branches, etc.) must be the same as (or implicitly convertible to) the return type of then-branch functor call @c f(). -@tparam Cond Static boolean nullary meta-function selecting which functor +@tparam Pred Static boolean nullary meta-function selecting which functor call to compile and execute. @return A call-if statement so else and else-if statements can be specified if needed. Ultimately this will return the return value of the functor call being compiled and executed. */ -template -call_if_statement call_if(Then f) { - return call_if_statement(f); +template +call_if_statement call_if(Then f) { + return call_if_statement(f); } /** @@ -413,18 +413,18 @@ Compile and execute a boolean nullary functor call if and only if the specified static condition is true, otherwise trivially return @c true. @see @RefSect{advanced_topics, Advanced Topics} @param f Boolean nullary templated functor. The functor call @c f() is - compiled and executed if and only if @c Cond is @c true. -@tparam Cond Static boolean condition selecting when the functor call should + compiled and executed if and only if @c Pred is @c true. +@tparam Pred Static boolean condition selecting when the functor call should be compiled and executed. @return Boolean value returned by @c f() if the static condition if true, otherwise simply return @c true (i.e., check trivially passed). */ -template -typename boost::enable_if_c::type +template +typename boost::enable_if_c::type condition_if_c(Then f, bool else_ = true) { return f(); } -template -typename boost::disable_if_c::type +template +typename boost::disable_if_c::type condition_if_c(Then f, bool else_ = true) { return else_; } /** @@ -434,15 +434,15 @@ Compile and execute a boolean nullary functor call if and only if the specified static condition is true, otherwise trivially return @c true. @see @RefSect{advanced_topics, Advanced Topics} @param f Boolean nullary templated functor. The functor call @c f() is - compiled and executed if and only if @c Cond::value is @c true. -@tparam Cond Static boolean nullary meta-function selecting when the functor + compiled and executed if and only if @c Pred::value is @c true. +@tparam Pred Static boolean nullary meta-function selecting when the functor call should be compiled and executed. @return Boolean value returned by @c f() if the static condition if true, otherwise simply return @c true (i.e., check trivially passed). */ -template +template bool condition_if(Then f, bool else_ = true) { - return condition_if_c(f, else_); + return condition_if_c(f, else_); } } } // namespace diff --git a/include/boost/contract/core/check_macro.hpp b/include/boost/contract/core/check_macro.hpp index 4bb1656..ed70e24 100644 --- a/include/boost/contract/core/check_macro.hpp +++ b/include/boost/contract/core/check_macro.hpp @@ -7,6 +7,10 @@ // 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 +/** @file +Macro for implementation checks. +*/ + // IMPORTANT: Included by contract_macro.hpp so must #if-guard all its includes. #include #ifndef BOOST_CONTRACT_NO_CHECKS diff --git a/include/boost/contract/core/constructor_precondition.hpp b/include/boost/contract/core/constructor_precondition.hpp index 4bf6769..72b27cd 100644 --- a/include/boost/contract/core/constructor_precondition.hpp +++ b/include/boost/contract/core/constructor_precondition.hpp @@ -7,6 +7,10 @@ // 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 +/** @file +Class to check constructor preconditions. +*/ + // IMPORTANT: Included by contract_macro.hpp so must #if-guard all its includes. #include #ifndef BOOST_CONTRACT_NO_PRECONDITIONS diff --git a/include/boost/contract/core/exception.hpp b/include/boost/contract/core/exception.hpp index 29ac794..deefc53 100644 --- a/include/boost/contract/core/exception.hpp +++ b/include/boost/contract/core/exception.hpp @@ -266,7 +266,6 @@ namespace exception_ { /* can throw */; void BOOST_CONTRACT_DETAIL_DECLSPEC entry_inv_failure_locked(from where) /* can throw */; - // Precondition failure. @@ -424,7 +423,7 @@ Set a new entry invariant failure handler and return the old one. @b Throws: @c noexcept (or @c throw() if no C++11). @param f New entry invariant failure handler functor. -@return Old entry invariant failure handler functor. +@return New failure handler @c f (for concatenating function calls). @see @RefSect{advanced_topics, Advanced Topics} */ inline from_failure_handler set_entry_invariant_failure(from_failure_handler @@ -478,7 +477,7 @@ Set a new precondition failure handler and return the old one. @b Throws: @c noexcept (or @c throw() if no C++11). @param f New precondition failure handler functor. -@return Old precondition failure handler functor. +@return New failure handler @c f (for concatenating function calls). @see @RefSect{advanced_topics, Advanced Topics} */ inline from_failure_handler set_precondition_failure(from_failure_handler @@ -557,7 +556,7 @@ Set a new exit invariant failure handler and return the old one. @b Throws: @c noexcept (or @c throw() if no C++11). @param f New exit invariant failure handler functor. -@return Old exit invariant failure handler functor. +@return New failure handler @c f (for concatenating function calls). @see @RefSect{advanced_topics, Advanced Topics} */ inline from_failure_handler set_exit_invariant_failure(from_failure_handler @@ -611,7 +610,7 @@ Set a new postcondition failure handler and return the old one. @b Throws: @c noexcept (or @c throw() if no C++11). @param f New postcondition failure handler functor. -@return Old postcondition failure handler functor. +@return New failure handler @c f (for concatenating function calls). @see @RefSect{advanced_topics, Advanced Topics} */ inline from_failure_handler set_postcondition_failure(from_failure_handler @@ -693,25 +692,13 @@ This is equivalent to calling both @b Throws: @c noexcept (or @c throw() if no C++11). @param f New invariant failure handler functor. +@return New failure handler @c f (for concatenating function calls). @see @RefSect{advanced_topics, Advanced Topics} */ -inline void set_invariant_failure(from_failure_handler const& f) +inline from_failure_handler set_invariant_failure(from_failure_handler const& f) /** @cond */ BOOST_NOEXCEPT_OR_NOTHROW /** @endcond */ { // This must be impl here for header-only linkage (HEADER_ONLY defined). - set_entry_invariant_failure(f); - set_exit_invariant_failure(f); -} - -// Cannot provide a `set_all_failures` because check handler has no `from`. -inline void set_specification_failure(from_failure_handler const& f) - /** @cond */ BOOST_NOEXCEPT_OR_NOTHROW /** @endcond */ { - // This must be impl here for header-only linkage (HEADER_ONLY defined). - set_entry_invariant_failure(f); - set_precondition_failure(f); - set_old_failure(f); - set_exit_invariant_failure(f); - set_postcondition_failure(f); - set_except_failure(f); + return set_entry_invariant_failure(set_exit_invariant_failure(f)); } } } // namespace diff --git a/include/boost/contract/detail/inlined/core/exception.hpp b/include/boost/contract/detail/inlined/core/exception.hpp index effbad9..16f3e07 100644 --- a/include/boost/contract/detail/inlined/core/exception.hpp +++ b/include/boost/contract/detail/inlined/core/exception.hpp @@ -118,9 +118,7 @@ namespace exception_ { failure_handler set_check_failure_unlocked(failure_handler const& f) BOOST_NOEXCEPT_OR_NOTHROW { - failure_handler result = check_failure_handler; - check_failure_handler = f; - return result; + return check_failure_handler = f; } failure_handler set_check_failure_locked(failure_handler const& f) @@ -155,9 +153,7 @@ namespace exception_ { from_failure_handler set_entry_inv_failure_unlocked( from_failure_handler const& f) BOOST_NOEXCEPT_OR_NOTHROW { - from_failure_handler result = entry_inv_failure_handler; - entry_inv_failure_handler = f; - return result; + return entry_inv_failure_handler = f; } from_failure_handler set_entry_inv_failure_locked( @@ -194,9 +190,7 @@ namespace exception_ { from_failure_handler set_pre_failure_unlocked(from_failure_handler const& f) BOOST_NOEXCEPT_OR_NOTHROW { - from_failure_handler result = pre_failure_handler; - pre_failure_handler = f; - return result; + return pre_failure_handler = f; } from_failure_handler set_pre_failure_locked(from_failure_handler const& f) @@ -231,9 +225,7 @@ namespace exception_ { from_failure_handler set_old_failure_unlocked(from_failure_handler const& f) BOOST_NOEXCEPT_OR_NOTHROW { - from_failure_handler result = old_failure_handler; - old_failure_handler = f; - return result; + return old_failure_handler = f; } from_failure_handler set_old_failure_locked(from_failure_handler const& f) @@ -268,9 +260,7 @@ namespace exception_ { from_failure_handler set_exit_inv_failure_unlocked( from_failure_handler const& f) BOOST_NOEXCEPT_OR_NOTHROW { - from_failure_handler result = exit_inv_failure_handler; - exit_inv_failure_handler = f; - return result; + return exit_inv_failure_handler = f; } from_failure_handler set_exit_inv_failure_locked( @@ -307,9 +297,7 @@ namespace exception_ { from_failure_handler set_post_failure_unlocked( from_failure_handler const& f) BOOST_NOEXCEPT_OR_NOTHROW { - from_failure_handler result = post_failure_handler; - post_failure_handler = f; - return result; + return post_failure_handler = f; } from_failure_handler set_post_failure_locked(from_failure_handler const& f) @@ -344,9 +332,7 @@ namespace exception_ { from_failure_handler set_except_failure_unlocked( from_failure_handler const& f) BOOST_NOEXCEPT_OR_NOTHROW { - from_failure_handler result = except_failure_handler; - except_failure_handler = f; - return result; + return except_failure_handler = f; } from_failure_handler set_except_failure_locked( diff --git a/include/boost/contract_macro.hpp b/include/boost/contract_macro.hpp index 8bfb838..259f9a3 100644 --- a/include/boost/contract_macro.hpp +++ b/include/boost/contract_macro.hpp @@ -2,6 +2,21 @@ #ifndef BOOST_CONTRACT_MACRO_HPP_ #define BOOST_CONTRACT_MACRO_HPP_ +// Copyright (C) 2008-2016 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 + +/** @file +Macro interface to completely disable contract code run-time and compile-time +overhead. + +Almost all the macros defined in this header file are variadic macros. On +compilers that do not support variadic macros, programmers can manually code +#ifndef BOOST_CONTRACT_NO_... statements (see +@RefSect{extra_topics, Extra Topics}). +*/ + // IMPORTANT: Following headers can always be #included (without any #if-guard) // because they expand to trivial code that does not affect compile-time. // IMPORTANT: Following header must always be #included here (without any @@ -30,30 +45,42 @@ // TODO: Make sure there are test for /all/ these macros (OLD_PTR_IF_COPYABLE, EXPECT, INVARIANT_VOLATILE, etc.). -// PRECONDITION(ftor,,,) #ifndef BOOST_CONTRACT_NO_PRECONDITIONS #define BOOST_CONTRACT_PRECONDITION(...) .precondition(__VA_ARGS__) #else + /** + Macro to program preconditions that can be completely disabled at + compile-time. + + BOOST_CONTRACT_PRECONDITION(f) expands to code equivalent to: + @code + #ifndef BOOST_CONTRACT_NO_PRECONDITIONS + .precondition(f) + #endif + @endcode + + Where: + @arg @b f is a nullary functor that checks preconditions. This is a + variadic macro parameter so it can contain commas not protected by + round parenthesis. + + @see @RefSect{tutorial, Tutorial}, @RefSect{extra_topics, Extra Topics} + */ #define BOOST_CONTRACT_PRECONDITION(...) /* nothing */ #endif -// OLD(ftor,,,) -// -// OLD_PTR[_IF_COPYABLE](type,,,)(name); // This is never (v, name)!! -// OLD_PTR[_IF_COPYABLE](type,,,)(name, value); -// OLD_PTR[_IF_COPYABLE](type,,,)(v, name, value); #ifndef BOOST_CONTRACT_NO_OLDS #include #include #include #include - #define BOOST_CONTRACT_OLD_VAR_1(name) \ - name - #define BOOST_CONTRACT_OLD_VAR_2(name, value) \ - name = BOOST_CONTRACT_OLDOF(value) - #define BOOST_CONTRACT_OLD_VAR_3(v, name, value) \ - name = BOOST_CONTRACT_OLDOF(v, value) + #define BOOST_CONTRACT_OLD_VAR_1(ptr) \ + ptr + #define BOOST_CONTRACT_OLD_VAR_2(ptr, expr) \ + ptr = BOOST_CONTRACT_OLDOF(expr) + #define BOOST_CONTRACT_OLD_VAR_3(v, ptr, expr) \ + ptr = BOOST_CONTRACT_OLDOF(v, expr) #define BOOST_CONTRACT_OLD_VAR_(...) \ BOOST_PP_CAT(BOOST_PP_OVERLOAD(BOOST_CONTRACT_OLD_VAR_, __VA_ARGS__) \ @@ -70,28 +97,180 @@ #else #include + /** + Macro to program old values that can be completely disabled at compile-time. + + This is an overloaded variadic macro and it can be used in a number of + different ways: + + 1\. BOOST_CONTRACT_OLD_PTR(T)(ptr) expands to code equivalent + to: + @code + #ifndef BOOST_CONTRACT_NO_OLDS + boost::contract::old_ptr ptr // Never requires `v`. + #endif + @endcode + + 2\. BOOST_CONTRACT_OLD_PTR(T)(ptr, expr) expands to code + equivalent to: + @code + #ifndef BOOST_CONTRACT_NO_OLDS + boost::contract::old_ptr ptr = BOOST_CONTRACT_OLDOF(expr) + #endif + @endcode + + 3\. BOOST_CONTRACT_OLD_PTR(T)(v, ptr, expr) expands to code + equivalent to: + @code + #ifndef BOOST_CONTRACT_NO_OLDS + boost::contract::old_ptr ptr = BOOST_CONTRACT_OLDOF(v, expr) + #endif + @endcode + + Where: + @arg @b T is the old value type. This type must be copy constructible + (i.e., boost::is_copy_constructible::value must be + @c true), otherwise this library will generate a compile-time error + if the old value pointer is dereferenced. This is a variadic macro + parameter so it can contain commas not protected by round + parenthesis. + @arg @b v is the extra parameter of type + boost::contract::virtual_* passed to the enclosing virtual + public function. + @arg @b ptr is the name of the old value pointer variable. + @arg @b expr is the expression to be evaluated and copied in the old + value. This is not a variadic macro parameter so any comma it might + contain must be protected by round parenthesis (this + BOOST_CONTRACT_OLD_PTR(T)(v, ptr, (expr)) will always work). + + @see @RefSect{tutorial, Tutorial}, @RefSect{extra_topics, Extra Topics} + */ #define BOOST_CONTRACT_OLD_PTR(...) BOOST_PP_TUPLE_EAT(0) + + /** + Macro to program old values that can be completely disabled at compile-time + (for old value types that might be non-copyable). + + This is an overloaded variadic macro and it can be used in a number of + different ways: + + 1\. BOOST_CONTRACT_OLD_PTR_IF_COPYABLE(T)(ptr) expands to code + equivalent to: + @code + #ifndef BOOST_CONTRACT_NO_OLDS + boost::contract::old_ptr_if_copyable ptr // Never requires `v`. + #endif + @endcode + + 2\. OOST_CONTRACT_OLD_PTR_IF_COPYABLE(T)(ptr, expr) expands to + code equivalent to: + @code + #ifndef BOOST_CONTRACT_NO_OLDS + boost::contract::old_ptr_if_copyable ptr = BOOST_CONTRACT_OLDOF(expr) + #endif + @endcode + + 3\. BOOST_CONTRACT_OLD_PTR_IF_COPYABLE(T)(v, ptr, expr) expands + to code equivalent to: + @code + #ifndef BOOST_CONTRACT_NO_OLDS + boost::contract::old_ptr_if_copyable ptr = + BOOST_CONTRACT_OLDOF(v, expr) + #endif + @endcode + + Where: + @arg @b T is the old value type. If this type is not copy + constructible (i.e., boost::is_copy_constructible::value + is @c false), the old value pointer will be set to null. This is a + variadic macro parameter so it can contain commas not protected by + round parenthesis. + @arg @b v is the extra parameter of type + boost::contract::virtual_* passed to the enclosing virtual + public function. + @arg @b ptr is the name of the old value pointer variable. + @arg @b expr is the expression to be evaluated and copied in the old + value. This is not a variadic macro parameter so any comma it might + contain must be protected by round parenthesis (but this + BOOST_CONTRACT_OLD_PTR(T)(v, ptr, (expr)); will always + work). + + @see @RefSect{extra_topics, Extra Topics} + */ #define BOOST_CONTRACT_OLD_PTR_IF_COPYABLE(...) BOOST_PP_TUPLE_EAT(0) + + /** + Macro to program old value copies at body that can be completely disabled at + compile-time. + + @c BOOST_CONTRACT_OLD(f) expands to code equivalent to: + @code + #ifndef BOOST_CONTRACT_NO_OLDS + .old(f) + #endif + @endcode + + Where: + @arg @b f is a nullary functor that assigns old pointers to old value + copies. This is a variadic macro parameter so it can contain commas + not protected by round parenthesis. + + @see @RefSect{advanced_topics, Advanced Topics}, + @RefSect{extra_topics, Extra Topics} + */ #define BOOST_CONTRACT_OLD(...) /* nothing */ #endif -// POSTCONDITION(ftor,,,) #ifndef BOOST_CONTRACT_NO_POSTCONDITIONS #define BOOST_CONTRACT_POSTCONDITION(...) .postcondition(__VA_ARGS__) #else + /** + Macro to program postconditions that can be completely disabled at + compile-time. + + BOOST_CONTRACT_POSTCONDITION(f) expands to code equivalent to: + @code + #ifndef BOOST_CONTRACT_NO_POSTCONDITIONS + .postcondition(f) + #endif + @endcode + + Where: + @arg @b f is a functor that checks postconditions. This function takes + the return value as its one single parameter but only for virtual + public functions and public functions overrides, otherwise it takes + no parameter. This is a variadic macro parameter so it can contain + commas not protected by round parenthesis. + + @see @RefSect{tutorial, Tutorial}, @RefSect{extra_topics, Extra Topics} + */ #define BOOST_CONTRACT_POSTCONDITION(...) /* nothing */ #endif -// EXCEPT(ftor,,,) #ifndef BOOST_CONTRACT_NO_EXCEPTS #define BOOST_CONTRACT_EXCEPT(...) .except(__VA_ARGS__) #else + /** + Macro to program exception guarantees that can be completely disabled at + compile-time. + + BOOST_CONTRACT_EXCEPT(f) expands to code equivalent to: + @code + #ifndef BOOST_CONTRACT_NO_EXCEPTS + .except(f) + #endif + @endcode + + Where: + @arg @b f is a nullary functor that checks exception guarantees. + This is a variadic macro parameter so it can contain commas not + protected by round parenthesis. + + @see @RefSect{tutorial, Tutorial}, @RefSect{extra_topics, Extra Topics} + */ #define BOOST_CONTRACT_EXCEPT(...) /* nothing */ #endif -// INVARIANT({ ,,, }) -// INVARIANT_VOLATILE({ ,,, }) -// STATIC_INVARIANT({ ,,, }) #ifndef BOOST_CONTRACT_NO_INVARIANTS #include @@ -102,72 +281,113 @@ #define BOOST_CONTRACT_STATIC_INVARIANT(...) \ static void BOOST_CONTRACT_STATIC_INVARIANT_FUNC() __VA_ARGS__ #else + /** + Macro to program (constant) class invariants that can be completely disabled + at compile-time. + + BOOST_CONTRACT_INVARIANT({ ... }) expands to code equivalent to: + @code + #ifndef BOOST_CONTRACT_NO_INVARIANTS + void BOOST_CONTRACT_INVARIANT_FUNC() const { + ... + } + #endif + @endcode + + Where: + @arg { ... } is the definition of the function that checks class + invariants (this can be a semicolon @c ; to separate this function + definition from its declaration as usual in C++). This is a variadic + macro parameter so it can contain commas not protected by round + parenthesis. + + @see @RefSect{tutorial, Tutorial}, @RefSect{extra_topics, Extra Topics} + */ #define BOOST_CONTRACT_INVARIANT(...) /* nothing */ + + /** + Macro to program volatile class invariants that can be completely disabled + at compile-time. + + BOOST_CONTRACT_INVARIANT_VOLATILE({ ... }) expands to code equivalent + to: + @code + #ifndef BOOST_CONTRACT_NO_INVARIANTS + void BOOST_CONTRACT_INVARIANT_FUNC() const volatile { + ... + } + #endif + @endcode + + Where: + @arg { ... } is the definition of the function that checks + volatile class invariants (this can be a semicolon @c ; to separate + this function definition from its declaration as usual in C++). This + is a variadic macro parameter so it can contain commas not protected + by round parenthesis. + + @see @RefSect{extra_topics, Extra Topics} + */ #define BOOST_CONTRACT_INVARIANT_VOLATILE(...) /* nothing */ + + /** + Macro to program static class invariants that can be completely disabled + at compile-time. + + BOOST_CONTRACT_STATIC_INVARIANT({ ... }) expands to code equivalent + to: + @code + #ifndef BOOST_CONTRACT_NO_INVARIANTS + static void BOOST_CONTRACT_STATIC_INVARIANT_FUNC() { + ... + } + #endif + @endcode + + Where: + @arg { ... } is the definition of the function that checks static + class invariants (this can be a semicolon @c ; to separate this + function definition from its declaration as usual in C++). This is a + variadic macro parameter so it can contain commas not protected by + round parenthesis. + + @see @RefSect{tutorial, Tutorial}, @RefSect{extra_topics, Extra Topics} + */ #define BOOST_CONTRACT_STATIC_INVARIANT(...) /* nothing */ #endif -// FUNCTION() [...] ; -#ifndef BOOST_CONTRACT_NO_FUNCTIONS - #include - #include - #include - - #define BOOST_CONTRACT_FUNCTION \ - boost::contract::check BOOST_CONTRACT_DETAIL_NAME2(c, __LINE__) = \ - boost::contract::function -#else - #include - - #define BOOST_CONTRACT_FUNCTION BOOST_PP_EMPTY -#endif - -// STATIC_PUBLIC_FUNCTION(class_type,,,) [...] ; -// -// PUBLIC_FUNCTION(obj) [...] ; -// PUBLIC_FUNCTION(v, obj) [...] ; -// PUBLIC_FUNCTION(v, r, obj) [...] ; -// -// PUBLIC_FUNCTION_OVERRIDE(override_type)(v, fptr, obj, args...) [...] ; -// PUBLIC_FUNCTION_OVERRIDE(override_type)(v, r, fptr, obj, args...) [...] ; -#ifndef BOOST_CONTRACT_NO_PUBLIC_FUNCTIONS - #include - #include - #include - - #define BOOST_CONTRACT_STATIC_PUBLIC_FUNCTION(...) \ - boost::contract::check BOOST_CONTRACT_DETAIL_NAME2(c, __LINE__) = \ - boost::contract::public_function< __VA_ARGS__ >() - - #define BOOST_CONTRACT_PUBLIC_FUNCTION \ - boost::contract::check BOOST_CONTRACT_DETAIL_NAME2(c, __LINE__) = \ - boost::contract::public_function - - #define BOOST_CONTRACT_PUBLIC_FUNCTION_OVERRIDE(override_type) \ - boost::contract::check BOOST_CONTRACT_DETAIL_NAME2(c, __LINE__) = \ - boost::contract::public_function -#else - #include - - #define BOOST_CONTRACT_STATIC_PUBLIC_FUNCTION(...) /* nothing */ - #define BOOST_CONTRACT_PUBLIC_FUNCTION BOOST_PP_TUPLE_EAT(0) - #define BOOST_CONTRACT_PUBLIC_FUNCTION_OVERRIDE(override_type) \ - BOOST_PP_TUPLE_EAT(0) -#endif - -// CONSTRUCTOR(obj) [...] ; #ifndef BOOST_CONTRACT_NO_CONSTRUCTORS #include #include #include - #define BOOST_CONTRACT_CONSTRUCTOR(obj) \ + #define BOOST_CONTRACT_CONSTRUCTOR(...) \ boost::contract::check BOOST_CONTRACT_DETAIL_NAME2(c, __LINE__) = \ - boost::contract::constructor(obj) + boost::contract::constructor(__VA_ARGS__) #else - #define BOOST_CONTRACT_CONSTRUCTOR(obj) /* nothing */ + /** + Macro to program contracts that can be completely disabled at compile-time + for constructors. + + BOOST_CONTRACT_CONSTRUCTOR(obj) expands to code equivalent to: + @code + #ifndef BOOST_CONTRACT_NO_CONSTRUCTORS + boost::contract::check internal_identifier = + boost::contract::constructor(obj) + #endif + @endcode + + Where: + @arg @b obj is a pointer to the object of from the enclosing constructor + scope (typically @c this). + @arg @b internal_identifier is a variable name internally generated by + this library (this is unique but only on different line numbers so + this macro cannot be used multiple times on the same line). + + @see @RefSect{tutorial, Tutorial}, @RefSect{extra_topics, Extra Topics} + */ + #define BOOST_CONTRACT_CONSTRUCTOR(...) /* nothing */ #endif -// CONSTRUCTOR_PRECONDITION(class_type,,,)(ftor,,,) #if !defined(BOOST_CONTRACT_NO_CONSTRUCTORS) && \ !defined(BOOST_CONTRACT_NO_PRECONDITIONS) // constructor_precondition.hpp already #included at top. @@ -175,25 +395,208 @@ boost::contract::constructor_precondition< __VA_ARGS__ > #else #include + // constructor_precondition.hpp always #included at top of this file. - // constructor_precondition.hpp already #included at top. + /** + Macro to program preconditions that can be completely disabled at + compile-time for constructors. + + BOOST_CONTRACT_CONSTRUCTOR_PRECONDITION(Class)(r) expands + to code equivalent to: + @code + #if !defined(BOOST_CONTRACT_NO_CONSTRUCTORS) && \ + !defined(BOOST_CONTRACT_NO_PRECONDITIONS) + boost::contract::constructor_precondition(r) + #else + // No-op call (likely optimized away, minimal to no overhead). + boost::contract::constructor_precondition() + #endif + @endcode + + Where: + @arg @b Class is the type of the enclosing constructor class. This is a + variadic macro parameter so it can contain commas not protected by + round parenthesis. + @arg @b r is a nullary functor that checks preconditions. This is handled + as a variadic macro parameter so it can contain commas not protected + by round parenthesis. + + @see @RefSect{tutorial, Tutorial}, @RefSect{extra_topics, Extra Topics} + */ #define BOOST_CONTRACT_CONSTRUCTOR_PRECONDITION(...) \ /* always use default ctor (i.e., do nothing) */ \ boost::contract::constructor_precondition< __VA_ARGS__ >() \ BOOST_PP_TUPLE_EAT(0) #endif -// DESTRUCTOR(obj) [...] ; #ifndef BOOST_CONTRACT_NO_DESTRUCTORS #include #include #include - #define BOOST_CONTRACT_DESTRUCTOR(obj) \ + #define BOOST_CONTRACT_DESTRUCTOR(...) \ boost::contract::check BOOST_CONTRACT_DETAIL_NAME2(c, __LINE__) = \ - boost::contract::destructor(obj) + boost::contract::destructor(__VA_ARGS__) #else - #define BOOST_CONTRACT_DESTRUCTOR(obj) /* nothing */ + /** + Macro to program contracts that can be completely disabled at compile-time + for destructors. + + BOOST_CONTRACT_DESTRUCTOR(obj) expands to code equivalent to: + @code + #ifndef BOOST_CONTRACT_NO_DESTRUCTORS + boost::contract::check internal_identifier = + boost::contract::destructor(obj) + #endif + @endcode + + Where: + @arg @b obj is a pointer to the object of from the enclosing destructor + scope (typically @c this). + @arg @b internal_identifier is a variable name internally generated by + this library (this is unique but only on different line numbers so + this macro cannot be used multiple times on the same line). + + @see @RefSect{tutorial, Tutorial}, @RefSect{extra_topics, Extra Topics} + */ + #define BOOST_CONTRACT_DESTRUCTOR(...) /* nothing */ +#endif + +#ifndef BOOST_CONTRACT_NO_PUBLIC_FUNCTIONS + #include + #include + #include + + #define BOOST_CONTRACT_PUBLIC_FUNCTION(...) \ + boost::contract::check BOOST_CONTRACT_DETAIL_NAME2(c, __LINE__) = \ + boost::contract::public_function(__VA_ARGS__) + + #define BOOST_CONTRACT_PUBLIC_FUNCTION_OVERRIDE(...) \ + boost::contract::check BOOST_CONTRACT_DETAIL_NAME2(c, __LINE__) = \ + boost::contract::public_function<__VA_ARGS__> + + #define BOOST_CONTRACT_STATIC_PUBLIC_FUNCTION(...) \ + boost::contract::check BOOST_CONTRACT_DETAIL_NAME2(c, __LINE__) = \ + boost::contract::public_function< __VA_ARGS__ >() +#else + #include + + /** + Macro to program contracts that can be completely disabled at compile-time + for (non-static and not overriding) public functions. + + BOOST_CONTRACT_PUBLIC_FUNCTION(param_list) expands to + code equivalent to: + @code + #ifndef BOOST_CONTRACT_NO_PUBLIC_FUNCTIONS + boost::contract::check internal_identifier = + boost::contract::public_function(param_list) + #endif + @endcode + + Where: + @arg @b param_list is the (overloaded) list of parameters normally passed + to @c boost::contract::public_function for non-static public + functions that do not override any virtual function. This is handled + as a variadic macro parameter so it can contain commas not protected + by round parenthesis. + @arg @b internal_identifier is a variable name internally generated by + this library (this is unique but only on different line numbers so + this macro cannot be used multiple times on the same line). + + @see @RefSect{tutorial, Tutorial}, @RefSect{extra_topics, Extra Topics} + */ + #define BOOST_CONTRACT_PUBLIC_FUNCTION(...) /* nothing */ + + /** + Macro to program contracts that can be completely disabled at compile-time + for public functions that override virtual functions. + + BOOST_CONTRACT_PUBLIC_FUNCTION_OVERRIDE(Override)(param_list) + expands to code equivalent to: + @code + #ifndef BOOST_CONTRACT_NO_PUBLIC_FUNCTIONS + boost::contract::check internal_identifier = + boost::contract::public_function(param_list) + #endif + @endcode + + Where: + @arg @b Override is the introspection type trait generated using + @c BOOST_CONTRACT_OVERRIDE, @c BOOST_CONTRACT_OVERRIDES, or + @c BOOST_CONTRACT_NAMED_OVERRIDE. This is a variadic macro parameter + so it can contain commas not protected by round parenthesis. + @arg @b param_list is the (overloaded) list of parameters normally passed + to @c boost::contract::public_function for public functions that + override virtual functions. This is handled as a variadic macro + parameter so it can contain commas not protected by round + parenthesis. + @arg @b internal_identifier is a variable name internally generated by + this library (this is unique but only on different line numbers so + this macro cannot be used multiple times on the same line). + + @see @RefSect{tutorial, Tutorial}, @RefSect{extra_topics, Extra Topics} + */ + #define BOOST_CONTRACT_PUBLIC_FUNCTION_OVERRIDE(...) \ + BOOST_PP_TUPLE_EAT(0) + + /** + Macro to program contracts that can be completely disabled at compile-time + for static public functions. + + BOOST_CONTRACT_STATIC_PUBLIC_FUNCTION(Class) expands to + code equivalent to: + @code + #ifndef BOOST_CONTRACT_NO_PUBLIC_FUNCTIONS + boost::contract::check internal_identifier = + boost::contract::public_function() + #endif + @endcode + + Where: + @arg @b Class is the type of the class of the enclosing static public + function. This is a variadic macro parameter so it can contain + commas not protected by round parenthesis. + @arg @b internal_identifier is a variable name internally generated by + this library (this is unique but only on different line numbers so + this macro cannot be used multiple times on the same line). + + @see @RefSect{tutorial, Tutorial}, @RefSect{extra_topics, Extra Topics} + */ + #define BOOST_CONTRACT_STATIC_PUBLIC_FUNCTION(...) /* nothing */ +#endif + +#ifndef BOOST_CONTRACT_NO_FUNCTIONS + #include + #include + #include + + #define BOOST_CONTRACT_FUNCTION() \ + boost::contract::check BOOST_CONTRACT_DETAIL_NAME2(c, __LINE__) = \ + boost::contract::function() +#else + #include + + /** + Macro to program contracts that can be completely disabled at compile-time + for (non-public) functions. + + BOOST_CONTRACT_FUNCTION() expands to code equivalent to: + @code + #ifndef BOOST_CONTRACT_NO_FUNCTIONS + boost::contract::check internal_identifier = + boost::contract::function() + #endif + @endcode + + Where: + @arg @b internal_identifier is a variable name internally generated by + this library (this is unique but only on different line numbers so + this macro cannot be used multiple times on the same line). + + @see @RefSect{tutorial, Tutorial}, @RefSect{extra_topics, Extra Topics} + */ + #define BOOST_CONTRACT_FUNCTION() /* nothing */ #endif #endif // #include guard diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index c9ba62f..74597fc 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -241,8 +241,8 @@ test-suite result : test-suite old : [ subdir-run old : auto ] - [ subdir-run old : no_macros ] - [ subdir-run old : no_macros_if_copyable ] + [ subdir-run old : no_macro ] + [ subdir-run old : no_macro_if_copyable ] [ subdir-compile-fail old : no_make_old_error ] [ subdir-compile-fail old : no_make_old_if_copyable_error ] diff --git a/test/old/no_macros.cpp b/test/old/no_macro.cpp similarity index 100% rename from test/old/no_macros.cpp rename to test/old/no_macro.cpp diff --git a/test/old/no_macros.hpp b/test/old/no_macro.hpp similarity index 100% rename from test/old/no_macros.hpp rename to test/old/no_macro.hpp diff --git a/test/old/no_macros_if_copyable.cpp b/test/old/no_macro_if_copyable.cpp similarity index 100% rename from test/old/no_macros_if_copyable.cpp rename to test/old/no_macro_if_copyable.cpp