diff --git a/doc/qbk/advanced_topics.qbk b/doc/qbk/advanced_topics.qbk index 70b49a0..e4c0afe 100644 --- a/doc/qbk/advanced_topics.qbk +++ b/doc/qbk/advanced_topics.qbk @@ -35,6 +35,8 @@ Similarly, `boost::optional` can be used for return values passed to virtual and [section Old Values at Body] +TODO + [import ../../example/features/old.cpp] [old] @@ -129,895 +131,296 @@ Furthermore, see __Class_Invariants__ and __Volatile_Public_Functions__ for prog [endsect] [section Volatile Public Functions] + +TODO + [endsect] [section Throw on Failure] + +[import ../../example/features/throw_on_failure.cpp] + +If a condition checked using [macroref BOOST_CONTRACT_ASSERT] is `false` or if code specified in preconditions, postconditions, and class invariants throw any exception, this library calls the /contract failure handler/ functions [funcref boost::contract::precondition_failed], [funcref boost::contract::postcondition_failed], [funcref boost::contract::entry_invariant_failed], or [funcref boost::contract::exit_invariant_failed] respectively (in fact, [macroref BOOST_CONTRACT_ASSERT] simply expand to code that throw [classref boost::contract::assertion_failure], see also __No_Macros__). + +By default, these handler functions 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 might be in a state for which no operation can be successfully performed, so the program should be stopped). +Therefore, that is what this library does by default. +However, for a specific application, programmers could implement some fail-safe mechanism for which some mission-critical operations can always be performed upon handling specific failures. +Therefore, 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_failed], [funcref boost::contract::set_postcondition_failed], [funcref boost::contract::set_entry_invariant_failed] and [funcref boost::contract::set_exit_exit_invariant_failed] (or just [funcref boost::contract::set_invariant_failed] to set both entry and exit invariant failure handlers at once). +For example (see also [@../../example/features/throw_on_failure.cpp =throw_on_failure.cpp=]): + +[throw_on_failure_handler] + +Note that 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 handler functions that can be used to identify if the contract failure occurred during a destructor, a constructor, or a function call. +This way programmers can ensure to never throw from a destructor call (in the example above, failures from destructors are simply ignored... in general, this is not a safe thing to do, but how to handle such a case in real code is left up to the specific applications being programmed). + +Then the contract assertions can be programmed to throw [classref boost::contract::assertion_failure] using [macroref BOOST_CONTRACT_ASSERT] (see also __No_Macro__), or any other exception using: + + if(``[^['error-condition]]``) throw ...; + +For example (see also [@../../example/features/throw_on_failure.cpp =throw_on_failure.cpp=]): + +[throw_on_failure_cstring] + [endsect] [section Separate Body Implementation] -[endsect] -[section Access] +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 will normally appear together with the function implementation code. +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 in any case (so it is not a real problem in practise). -* base_types -* invariant() and static_invariant() +In some cases, it might be desirable to completely separate the contract code from the code that implements the function body implementation code. +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 being extracted from the source code and presented as part of the documentation of the shipped software). -[classref BOOST_CONTRACT_OVERRIDE] must not necessarily be used in a `public` section of the class (e.g., it can be used in a `private` section in cases when all `public` members of a class must be controlled exactly). +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 file 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 originally constructors are actually defined). -For example: +For example, the following header file only contains function declarations and contract code (see also [@../../example/features/separate_body.hpp =separate_body.hpp=]): - class a - #define BASES public b - : BASES - { // In private section. - friend class boost::contract::access; +[import ../../example/features/separate_body.hpp] +[separate_body_hpp] - typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types; - #undef BASES +Instead, the code implementing the function bodies is programmed in a separate source file (see also [@../../example/features/separate_body.cpp =separate_body.cpp=]): - void invariant() const { /* ... */ } - static void static_invariant() { /* ... */ } +[import ../../example/features/separate_body.cpp] +[separate_body_cpp] - BOOST_CONTRACT_OVERRIDE(f) - - public: // Public section not altered by contracts. - void f(boost::contract::virtual_* v = 0) /* override */ { - auto c = boost::contract::public_function( - v, &a::f, this); - /* ... */ - } - }; +The same technique can be used for free, private, and protected functions. [endsect] -[section Override Trait] +[section Overloads and Named Overrides] -Calls to [funcref boost::contract::public_function] from different overloaded functions reuse the same `override_`[^['function-name]] template argument so [macroref BOOST_CONTRACT_OVERRIDE][^(['function-name])] is used only once in a given class even if [^['function-name]] is overloaded. +Calls to [funcref boost::contract::public_function] from different overloaded functions reuse the same `override_`[^['function-name]] template argument. +Therefore, [macroref BOOST_CONTRACT_OVERRIDE][^(['function-name])] is used only once in a given class even when [^['function-name]] is overloaded. For example (see also [@../../example/features/override_overload.cpp =override_overload.cpp=]): [import ../../example/features/override_overload.cpp] [override_overload] -Note that the function name passed to [macroref BOOST_CONTRACT_OVERRIDE] should not start with an underscore to avoid generating named with double underscores `override__...` that are reserved by the C++ standard. -There is a separate macro [macroref BOOST_CONTRACT_OVERRIDE_TRAIT] that can be used to explicitly specify the name of the trait that will be passed as [funcref boost::contract::public_function] template argument separately from the function name. -This macro can be used for function names that start with an underscore, when the name `override_`[^['function-name]] clashes with other names the user-define class, or in any other case when programmers want to use a name different than `override_...`. -For example (see also [@../../example/features/override_trait.cpp =override_trait.cpp=]): +Note that 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.* +It is best to use a different macro name [macroref BOOST_CONTRACT_NAMED_OVERRIDE] 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 macros would prevent using this library on compilers that do not support variadic macros (see also __No_Macros__). +] -[import ../../example/features/override_trait.cpp] -[override_trait] + BOOST_CONTRACT_OVERRIDE(``[^['function-name]]``) // Generate `override_...`. + BOOST_CONTRACT_NAMED_OVERRIDE(``[^['type-name]]``, ``[^['function-name]]``) + +This second macro can be used for function names that start with an underscore `_...`, when the name `override_`[^['function-name]] clashes with another name the user class, or in any other case when programmers need to generate a name different than `override_...`. +For example (see also [@../../example/features/named_override.cpp =named_override.cpp=]): + +[import ../../example/features/named_override.cpp] +[named_override] + +[endsect] + +[section Access] + +As we have seen, this library requires programmers to augment their classes declaring special members that are internally used to implement contracts: + +* The `invariant` and `static_invariant` member functions (used by this library to check class invariants). +* The `base_types` member type (used by this library to implement subcontracting). +* The `override_`[^['function-name]] member type (used by this library to implement subcontracting for overriding functions). + +Normally, some of these members must be public in order to be accessible by this library. +However, in some cases programmers might need to exactly control the public members of their classes in order to prevent users from incorrectly accessing encapsulated members (this might be especially true in large projects). + +`override_`[^['function-name]] never needs to be `public` and programmers can always declare it using [macroref BOOST_CONTRACT_OVERRIDE] in a `private` (or `protected`) section of the class. +[footnote +*Rationale.* +The internals of the `override_...` type generated by [macroref BOOST_CONTRACT_OVERRIDE] use names reserved by this library to users are not able to actually use such a type even when it is defined as a `public` member. +In theory, using C++14 generic lambdas, the [macroref BOOST_CONTRACT_OVERRIDE] macro could be re-implemented in a way so it can be expanded at function scoped (instead of class scoped). +] +`invariant`, `static_invariant`, and `base_types` normally need to be `public`, but programmers can declare them in a `private` (or `protected`) section of the class as long as they also declare the [classref boost::contract::access] class as `friend`. +For example (see also [@../../example/features/access.cpp =access.cpp=]): + +[import ../../example/features/access.cpp] +[access] + +This technique is not used in most examples of this documentation only for brevity, but programmers are encouraged to use it in real code. + +See also __Base_Types__, __Class_Invariant__, and __Overloads_and_Named_Override__ to declare these members with different names (e.g., when they clash with other names in the user-defined class). [endsect] [section Assertion Requirements (Call-If)] -[endsect] -[section No Lambda Functions (No C++11)] +In general, assertions can introduce a new set of requirements on the types used by the program: Some of the type requirements might be necessary only to program 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, and 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. +With this library, this can be done using [funcref boost::contract::call_if] and [funcref boost::contract::call_if_c]. + +For example, let's consider the STL `vector` class template. +This class template (as specified by the STL without the contracts) does not normally require that `T` has an equality operator `==` (it only requires `T` to be copy constructible). +However, the full contracts of the `vector::push_back(value)` member function include a postcondition `back() == value` which introduces the new requirement that `T` must have an equality operator `==`. +Programmers can specify this postcondition as-is 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::call_if] so to check the assertion only for types `T` that have an equality operator `==`, and trivially check `true` otherwise (see also [@../../example/features/call_if.cpp =call_if.cpp=]): + +[import ../../example/features/call_if.cpp] +[call_if] + +[funcref boost::contract::call_if] takes a condition template parameter as a boolean meta-function. +It takes a "then" nullary functor `t`, it calls and returns `t()` when the boolean meta-function evaluates to `true` at compile-time (thus `t()` must be valid code only in this case). +It provides an `else_` member to specify an "else" nullary functor `e`, it calls and returns `e()` when the boolean meta-function evaluates to `false` at compile-time (thus `e()` must be valid code only in this case). +It also provides an `else_if` member that can be used (multi times) to specify other boolean meta-function conditions and "then" and "else" nullary functors to be evaluated and valid only when the boolean meta-function is `false` at compile-time. +`else_` and `else_if` are optional if `t()` return value is `void` (otherwise the return types of `t()`, `e()`, and all the other nullary functors passed to `else_if` must all be compatible). +(There are also alternative versions named [funcref boost::contract::call_if_c] and `else_if_c` that take boolean constants instead of boolean meta-function conditions as template parameters.) + + boost::contract::call_if<``[^['boolean-meta-function-1]]``>( + ``[^['then-nullary-functor-1]]`` + ).else_if<``[^['boolean-meta-function-2]]``>( // Optional. + ``[^['then-nullary-functor-2]]`` + ) + ``[^['...]]`` // Else-if can be repeated zero or more times. + .else_( // Optional for functors returning `void`. + ``[^['else-nullary-functor]]`` + ) + +Therefore, the above `push_back` example calls (via `bind`) the functor `std::equal_to()(boost::cref(back()), boost::cref(value))` that checks the postcondition `back() == value` requiring `T`'s equality operator `==`, but only when the `boost::has_equal` meta-function evaluates to `true` at compile-time. +Otherwise, the lambda function `[] { return true; }` is used to trivially evaluate the postcondition assertion to be `true` when `T` does not have an equality operator `==`. + +[heading Old Value Requirements] + +TODO + +[heading Static-If (C++14)] + +[funcref boost::contract::call_if] is a general-purpose facility and it can be used together with C++14 generic lambdas to implement statements similar to `static if` (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 implemented via [funcref boost::contract::call_if] (see also [@../../example/features/static_if_cxx14.cpp =static_if_cxx14.cpp=]): + +[import ../../example/features/static_if_cxx14.cpp] +[static_if_cxx14] + +This implementation is much more concise, easy to read and maintain than the usual implementation of `std::advance` that uses tag dispatching. +[footnote +`boost::hana::if_` can also be used to emulate function scope `static if` with C++14 generic lambdas. +] + [endsect] [section No Macros (No C++11)] -[endsect] -[section ---------------------------------------------------------------------] -[endsect] +[import ../../example/features/no_macros.cpp] -[section Commas and Leading Symbols in Macros] +This section illustrates how to write contracts without using this library macros and programming the related code manually instead (a part from [macroref BOOST_CONTRACT_OVERRIDE] and [macroref BOOST_CONTRACT_NAMED_OVERRIDE] that cannot be programmed manually). -C++ macros cannot correctly parse a macro parameter if it contains a comma `,` that is not wrapped within round parenthesis `()` (because the preprocessor interprets such a comma as separation between two distinct macro parameters instead that as part of one single macro parameter, see also __Boost_Utility_IdentityType__). -Furthermore, syntactic elements specified to this library macros cannot start with a non-alphanumeric symbol (`-1`, `1.23`, `"abc"`, `::`, etc). -[footnote -Note that for the preprocessor a number with decimal period `1.23`, `0.12`, `.34` is considered a symbol (because its concatenation will not result in a valid macro identifier). -] -For example, the parameter type `::std::pair const&` cannot be passed to this library for two reasons: It starts with the non-alphanumeric symbol `::` and it contains the comma `OtherKey, OtherT` which is not wrapped by round parenthesis. +Some of this library macros are variadic macros, others are not (see below). +Variadic macros were officially added to the language since C++11. +However, C++ 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 this section can be considered more of a curiosity than anything else because programmers should seldom need to use this library without its macros. -The __Boost_Utility_IdentityType__ macro `BOOST_IDENTITY_TYPE` can be used as usual to overcome this issue. -However, using the `BOOST_IDENTITY_TYPE` macro presents two limitations: It makes the syntax of this library macros more cumbersome and, more importantly, it does not allow C++ to automatically deduce function template parameters (see __Boost_Utility_IdentityType__ for more information). -Therefore, the syntax of this library provides an alternative to `BOOST_IDENTITY_TYPE` to handle commas and leading symbols within macro parameters: +[heading Overrides (Not Variadic)] -# Commas and leading symbols can be used freely within elements of the syntax that already require wrapping parenthesis (e.g., non-fundamental parameter types `(::std::pair const&)`). -# Extra parenthesis can always be used to wrap elements of the syntax that might contain commas and leading symbols (e.g, the base class type `public (::sizeable)`). -# Extra parenthesis can always be used to wrap value expressions so they can contain commas and leading symbols (e.g., a class invariants assertion `(::sizeable::max_size >= size())`). - -For example (see also [file example/contracts macro_commas_symbols_integral_map.cpp]): - -[import ../example/contracts/macro_commas_symbols_integral_map.cpp] -[macro_commas_symbols_integral_map] - -(Concepts and other advanced constructs used in this example are explained in the rest of this section and in later sections of this documentation.) - -All these extra wrapping parenthesis are optional when there is no unwrapped comma and no leading symbol. -Programmers could chose to always program the extra parenthesis for consistency but it is the authors' opinion that the syntax is harder to read with the extra parenthesis so it is recommended to use them only when strictly necessary. - -It is also recommended to avoid using commas and leading symbols whenever possible so to limit the cases when it is necessary to use the extra wrapping parenthesis. -For example, in many cases the leading symbol `::` might not be necessary and leading symbols like `!` can be replaced by the alternative keywords like `not`. -Furthermore, in some cases `typedef` can be programmed just before class and function declarations to avoid passing types within multiple template parameters separated by commas. -Declarations of class templates and function templates are the most common cases were commas cannot be avoided and extra wrapping parenthesis are necessarily used. - -[warning -Preconditions, postconditions, and class invariants composed of one single assertion that needs to be wrapped within extra parenthesis need to use double parenthesis (this should be a relatively rare case). +As shown in __Overriding_Public_Functions__ and __Overloads_and_Named_Overrides__, this library provides the [macroref BOOST_CONTRACT_OVERRIDE] and [macroref BOOST_CONTRACT_NAMED_OVERRIDE] macros to program overriding public functions. +These macros cannot be programmed manually, but these are not variadic macros and programmers should never need not to use them. [footnote *Rationale.* -This limitation is introduced by the need to support also the sequence syntax for preprocessor without variadic macros (see the __No_Variadic_Macros__ section). -] -This is the case in the above example for `precondition( ((!full())) )` (but note that these extra parenthesis could have been avoided all together simply using `not` instead of `!` as in the more readable `precondition( not full() )`). +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). ] -[endsect] +[heading Assertions (Not Variadic)] -[section Static Assertions] +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, this macro: -This library allows to use [@http://en.wikipedia.org/wiki/C%2B%2B11#Static_assertions /static assertions/] to program preconditions, postconditions, class invariants, and block invariants so that they are checked at compile-time instead of at run-time. -The __CXX11__ syntax is used (but __Boost_MPL__ `BOOST_MPL_ASSERT_MSG` is used to implement static assertions so no __CXX11__ feature is required): + BOOST_CONTRACT_ASSERT(``[^['boolean-condition]]``) - static_assert(``/constant-boolean-condition/``, ``/constant-string-literal/``) +Simply expands to code equivalent to the following: -For example (see also [file example/contracts static_assertion_memcopy.cpp]): - -[import ../example/contracts/static_assertion_memcopy.cpp] -[static_assertion_memcopy] - -Static assertions are always checked at compile-time (regardless of them appearing in preconditions, postconditions, etc). -However, static assertions can be selectively disabled depending on where they are specified using [macroref CONTRACT_CONFIG_NO_PRECONDITIONS], [macroref CONTRACT_CONFIG_NO_POSTCONDITIONS], etc so it is still important to logically associate them with preconditions, postconditions, etc. - -The string message passed as the second parameter of `static_assert` is ignored by the current implementation of this library (but it could be used by future revisions of this library that take advantage of __CXX11__ features). -It is recommended to always specify meaningful messages for static assertions to increase the readability and documentation of contracts. -Similarly, it might be useful to put a short code comment following each assertions (`// pointer not null`, etc) to increase contract readability and documentation. -[footnote -*Rationale.* -__Eiffel__ supports /assertion labeling/ to further document assertions. -However, when designing this library for C++, the authors judged that it is sufficient to add a short code comment after each assertion to achieve a similar effect. -] - -In case of a static assertion failure, this library will generated a compile-time error containing text similar to the following: - -[pre -static_assertion_memcopy.cpp:18 ... ERROR_statically_checked_precondition_number_1_failed_at_line_18 ... -] - -This message is similar to the run-time assertion errors generated by this library, note how it contains all the information to uniquely identify the assertion that failed. - -[endsect] - -[section Constant Assertions] - -As explained in the __Constant_Correctness__ section, contract assertions shall not change the state of the program because contracts are only supposed to check (and not to alter) the state of the program. -This library automatically makes member functions, function parameters, function result, and old values constant so the compiler will correctly generate an error if assertions mistakenly try to change the object, the function parameters, the function result, or the old values (this should be sufficient in most cases when programming contracts). - -[important -This library cannot automatically make constant other variables that might be accessible by the contract assertions (e.g., global and static variables). -[footnote -*Rationale.* -The library needs to know at least the variable name in order to make it constant. -There is no way for this library to know the name of a global variable that is implicitly accessible from the contract assertion scope so such a variable cannot be automatically made constant. -Non-static data members are automatically made constant by making constant the member function that checks the contract, but that does not apply to static data members. -Not even __CXX11__ lambda implicit captures could be used in this context because they make variables constant only when captured by value and that introduces a __CopyConstructible__ requirement of the captured variable types. -] -] - -This library provides /constant assertions/ that can be used by programmers to explicitly make constant the variables used by the asserted boolean expression: - - const( ``/variable1/``, ``/variable2/``, ...) ``/boolean-expression-using-variable1-variable2-.../`` - -The following example calculates the next even and odd numbers that are stored (for some reason) in a global variable and static data member respectively (see also [file example/contracts const_assertion_number.cpp]): - -[import ../example/contracts/const_assertion_number.cpp] -[const_assertion_number] - -Note know the postconditions use constant assertions to force the `even` and `odd` variables to be constant within each boolean expression that evaluates the assertion. -If for example the assignment operator `=` were mistakenly used instead of the equality operator `==` in the above postconditions, the compiler would correctly generate an error. - -[endsect] - -[section Select Assertions] - -In the __Tutorial__ section we have used the ternary operator `:?` to program assertions that are guarded by a boolean condition: - - old_found ? true : std::find(begin(), end(), id) != end(), - old_found ? true : size() == old_size + 1 - -However, in cases like this one when the same boolean condition guards multiple assertions, it might be more efficient to evaluate the guard condition only once using one /select assertion/ instead of multiple ternary operators `:?`. -In addition, some programmers might find the select assertion syntax more readable than the ternary operator `:?`. -For example, the above guarded assertions could have been programmed using select assertions as: - - if(not old_found) ( // Guard condition evaluated only once. - std::find(begin(), end(), id) != end(), - size() == old_size + 1 - ) - -Select assertion allow to specify an optional else-block: - - if(``/boolean-condition/``) ( // Round parenthesis `()`. - ... // Comma-separated assertions. - ) else ( // Else optional as usual. - ... // Comma-separated assertions. - ) - -Note that round parenthesis `( ... )` are used to program the then-block and else-block instead of the usual C++ curly parenthesis `{ ... }`: -Select assertions can be nested into one another (the [macroref CONTRACT_LIMIT_NESTED_SELECT_ASSERTIONS] macro specifies the maximum nesting level for select assertions). - -For example, consider the postconditions of the following function which calculates the factorial of a natural number (see also [file example/contracts select_assertion_factorial.cpp]): - -[import ../example/contracts/select_assertion_factorial.cpp] -[select_assertion_factorial] - -Using the same syntax used for constant assertions, it is possible to force all variables (global, static, etc) used to evaluate the if-condition of the select assertion to be constant (see also [file example/contracts const_select_assertion_factorial.cpp]): - -[import ../example/contracts/const_select_assertion_factorial.cpp] -[const_select_assertion_factorial] - -[endsect] - -[section Assertion Statements] - -Only assertions can be programmed within the contracts while normal C++ statements are not allowed. -This is keeps contracts simple making programming errors within the contracts less likely and therefore increasing the probably that error-free contracts can properly check the correctness of the implementation. - -However, `using` directives, `namespace` aliases, and `typedef` statements are allowed within the contracts because they only affect compilation (not altering the state of the program at run-time) and they can be used to write more readable contracts (for example, shortening namespaces within contract assertions). -When used, these statements have effect only locally within the preconditions, postconditions, class invariants, etc where they appear. -[footnote -Assertion statements might be especially useful because contracts appear with the class and function declarations usually in header files where `using` directives and `namespace` aliases should only be used with extreme care and, for example, at local scope as assertion statements allow to do. -] - -For example (see also [file example/contracts assertion_statement_ialloc.cpp]): - -[import ../example/contracts/assertion_statement_ialloc.cpp] -[assertion_statement_ialloc] - -These statements follow their usual C++ syntax but they are terminated with a comma `,` instead of a semicolon `;`. -(The `BOOST_IDENTITY_TYPE` macro can be used to wrap eventual commas within the `typedef` statement.) - -[endsect] - -[section Assertion Requirements] - -In general, programming contract 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 program the assertions and they might not be required by the implementation itself. -In such cases, if the code is compiled with contracts disabled ([macroref CONTRACT_CONFIG_NO_PRECONDITIONS], etc), the program might compile but it might no longer compile when contracts are enabled because some of the types do not provide all the operations necessary to check the contract assertions. - -# More in general, 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 the contracts (because it is not possible to fully check the correctness of the program). -In these cases, programmers specify contract assertions as we have seen so far (and maybe even use concepts to explicitly specify the contract type requirements, see the __Concepts__ section). -# However, in other cases it might be desirable that adding contracts to a program does not change its type requirements and that assertions are simply not checked when the types do not provide all the operations necessary to evaluate the asserted conditions. -In these cases, programmers can use /assertion requirements/ to disable compilation and run-time checking of specific assertions: -[footnote -*Rationale.* -The assertion requirement syntax takes a constant boolean expression instead of a nullary boolean meta-function because the authors have found no reason to use a meta-function in this context. -Furthermore, constant boolean expressions can be manipulated via the usual operators `not`, `and`, etc, therefore more naturally than boolean meta-functions which need to use `boost::mpl::not_`, `boost::mpl::and_`, etc instead. -] - - ``/assertion/``, requires ``/constant-boolean-expression/`` - -(The constant boolean expression of an assertion requirement can be wrapped within round parenthesis `()` if it contains unwrapped commas.) - -Let's consider the STL `std::vector` class template. -This template normally does not require the value type `T` to be __EqualityComparable__ (i.e., to have an equality operator `==`), it only requires `T` to be __CopyConstructible__ (i.e., to have a copy constructor). -However, in order to check the following `std::vector::push_back` postcondition the type `T` must to be __EqualityComparable__: - - back() == value // Compiler error if not `EqualityComparable`. - -Therefore, the __EqualityComparable__ requirement on `T` is introduced only by the contract assertions and it is not required by the `std::vector` implementation. - -In some cases, programmers might want compilation to fail when `T` is not __EqualityComparable__ because in these cases it is not possible to fully check the `std::vector` contracts and therefore its correctness (in these cases programmers do not specify assertion requirements and let the compilation fail, or even better programmers can explicitly specify the assertion type requirements using concepts which will also fail compilation but hopefully with more informative error messages, see the __Concepts__ section). - -However, in other cases programmers might want to use the contracted version of `std::vector` exactly as they use the non-contracted version of the template and therefore without failing compilation if `T` is not __EqualityComparable__. -This can be achieved specifying assertion requirements for the `std::vector::push_back` postcondition: - - back() == value, requires boost::has_equal_to::value // No error if not `EqualityComparable`. - -This postcondition will be checked only when `T` is __EqualityComparable__, otherwise the postcondition will be ignored causing no compilation error. - -For example (see also [file example/contracts assertion_requirements_push_back.cpp]): -[footnote -Future revisions of this library might provide wrappers that program contracts for the STL in appropriate header files =contract/std/vector.hpp=, =contract/std/algorithm.hpp=, etc (see also [@http://www.sgi.com/tech/stl/ SGI STL] and [@http://sourceforge.net/apps/trac/contractpp/ticket/47 Ticket 47]). -However, given that STL implementations are usually considered to be ["correct], it is not clear if STL class invariants and postconditions would add any value, maybe programmers would only find STL preconditions useful. -] - -[import ../example/contracts/assertion_requirements_push_back.cpp] -[assertion_requirements_push_back] -[assertion_requirements_push_back_call] - -The `i.push_back(123)` call will check the postcondition `back() == value` because `int` is __EqualityComparable__ and the assertion requirement `boost::has_equal_to::value` is true. -However, the `n.push_back(num(123))` call will not check, and in fact not even compile, the postconditions `back() == value` because `num` is not __EqualityComparable__ and the assertion requirement `boost::has_equal_to::value` is false. -[footnote -Assertion requirements where first introduced by this library and they are not supported by __N1962__, __D__, or __Eiffel__ (even if they all allow to write contracts for templates). -Based on the authors' experience, assertion requirements are necessary for a language that make extensive use of templates like C++. -Furthermore, C++ does not automatically define equality operators `==` while it automatically defines copy constructors and that makes the use of the assertion requirements for __EqualityComparable__ a rather common practise (in __Eiffel__ instead types can be both copied and compared for equality by default). -It has been argued that it is not possible to check a program for correctness if types that are copyable cannot also be compared for equality and the authors experience with programming contracts confirms such an argument. -] - -The __Boost_TypeTraits__ library provides a set of meta-functions that are very useful to program assertion requirements. -[footnote -As of __Boost__ 1.50, `boost::has_equal_to` and similar traits always return true for an STL container even if the value type of the container does not have an operator `==`. -This is arguably a defect of the STL that always defines an operator `==` for its containers even when a container template is instantiated with a value type that has no operator `==`, in which case the container operator `==` will produce a compiler error (the STL should instead use __SFINAE__ to disable the declaration of the container operator `==` when the value type has no operator `==`). -Future versions of __Boost_TypeTraits__ will probably specialize `boost::has_equal_to` and similar traits to work around this behaviour of the STL. -In the meanwhile, programmers can specialize these traits themselves if needed: -`` -// Header: std_has_equal_to.hpp -#include -#include -#include -#include - -// STL defines `operator==` only between two identical containers (same value -// type, allocator, etc) and returning a type convertible to `bool`. - -namespace boost { - -// Specializations for `std::vector`. - -template< typename T, class Alloc > -struct has_equal_to < std::vector, std::vector > : - has_equal_to -{}; - -template< typename T, class Alloc, typename Ret > -struct has_equal_to < std::vector, std::vector, Ret > : - mpl::and_< - has_equal_to - , is_convertible - > -{}; - -// ... specialize `has_equal_to` for more STL containers. - -} // namespace -`` -] -However, C++ does not allow to inspect every trait of a type so there might be some assertion requirements that unfortunately cannot be programmed within the language. - -Another interesting use of assertion requirements is to model assertion computational complexity. -In some cases, checking assertions can be as computationally expensive as executing the function body or even more. -While preconditions, postconditions, etc can be disabled in groups at compile-time to improve performance (using [macroref CONTRACT_CONFIG_NO_PRECONDITIONS], [macroref CONTRACT_CONFIG_NO_POSTCONDITIONS], etc), it is also useful to be able to disable only specific assertions that are very computationally expensive while keeping all other preconditions, postconditions, etc enabled. -For example (see also [file example/contracts assertion_complexity_factorial.cpp]): - -[import ../example/contracts/assertion_complexity_factorial.cpp] -[assertion_complexity_factorial] - -In this case the postcondition `result = n * factorial(n - 1)` has factorial computational complexity and it is compiled and checked at run-time only if the macro `COMPLEXITY_MAX` is defined to be `O_FACTN` or greater. -Similarly, macros like `O_SMALLER_BODY`, `O_BODY`, and `O_GREATER_BODY` could have been defined to express computational complexity in relative terms with respect to the body computational complexity (see the __Examples__ section). -[footnote -__N1866__, an earlier version of __N1962__, introduced the notion of /importance ordering/ that could be used to selectively disable assertions that where too expensive computationally. -Importance ordering was then dropped by __N1962__. -Among other things, assertion requirements can be used to achieve the importance ordering functionality. -] - -Assertion requirements can be used with assertions, constant assertions, and static assertions but they cannot be used with assertion statements and with the if-condition of select assertions (however, if select assertions are programmed using the ternary operator `:?` then assertion requirements will disable the entire ternary operator `:?` expression including its if-condition). - -[endsect] - -[section Old-Of Requirements] - -Assertion requirements can be specified also for postconditions that use old values. -However, old values have the additional requirement that the type of the expression passed to the [macroref CONTRACT_OLDOF] macro must be __ConstantCopyConstructible__. -If such a requirement is not met: - -# Either, programmers want the compiler to error because the postconditions using the old value cannot be evaluated (in which case programmers will not specify assertion requirements and they might explicitly specify type requirements using concepts so to get more informative error messages, see the __Concepts__ section). -# Or, programmers want the old value declaration that uses the [macroref CONTRACT_OLDOF] macro to have no effect (because the old value cannot be copied) and the postconditions using such an old value to not be evaluated. - -Unfortunately, C++ cannot automatically detect if a type has a copy constructor therefore a special trait [classref contract::has_oldof] has to be introduced to support this second case. -The `contract::has_oldof` trait is a unary boolean meta-function which is `boost::mpl::true_` by default for any type `T` and it must be specialized by programmers for types which old values cannot be copied. - -For example, consider the following increment function (see also [file example/contracts has_oldof_inc.cpp]): - -[import ../example/contracts/has_oldof_inc.cpp] -[has_oldof_inc] -[has_oldof_inc_call] - -In this example, the `num` type is non-copyable so the `contract::has_oldof` specialization inherits from `boost::mpl::false_`. -As a consequence, the call `inc(n, m)` will automatically skip the old value declaration: - - auto old_value = CONTRACT_OLDOF value - -The following postcondition will also be skipped because its assertion requirement lists `contract::has_oldof` (where `T` is indeed the type of `value` passed to the [macroref CONTRACT_OLDOF] macro): - - value == old_value + offset, requires contract::has_oldof::value and ... - -Note how this postcondition actually requires the type `T` to have an old value, a plus operator `+`, and an equality operator `==` thus all of these requirements are programmed in the assertion requirements. - -Finally, return value declarations are never skipped so there is no `has_result` trait. -[footnote -*Rationale.* -The result type needs to be copyable in order for the function itself to return a value so this library can always evaluate return value declarations. -] - -[endsect] - -[section Old and Result Value Copies] - -This library uses the class template [classref contract::copy] to copy old values and the result value for postconditions. - - namespace contract - { - template< typename T > - class copy - { - public: copy ( T const& object ) ; - public: T const& value ( void ) const ; - }; - } // namespace - -The default implementation of the [classref contract::copy] class template requires that the type of the old value expression passed to the [macroref CONTRACT_OLDOF] macro and the result type are __ConstantCopyConstructible__ (i.e., these types provide a copy constructor that copies the object from a constant reference, the reference has to be constant so to ensure the constant-correctness of the copy operations that are executed within the contracts, see also the __Constant_Correctness__ section): - - // `ConstantCopyConstructible` (which implies `CopyConstructible`): - T::T ( T const& source ) ; // OK: constant-correct copy constructor. - - // `CopyConstructible` (but not `ConstantCopyConstructible`): - T::T ( T& source ) ; // Error, copy constructor is not constant-correct. - -Programmers can specialize the [classref contract::copy] class template to allow old value and result value copies even for types that are not __ConstantCopyConstructible__ (in this case it is the programmers' responsibility to make sure that the copy operations that they define are constant-correct, otherwise the contracts will no longer be constant-correct). -[footnote -Currently, it is not possible to force constant-correctness of the expression passed to the [macroref CONTRACT_OLDOF] macro. -Future revisions of this library will support `CONTRACT_OLDOF const( ... ) ...` to allow to make constant all variables (including global, static, etc) used by old value expressions (see also [@http://sourceforge.net/apps/trac/contractpp/ticket/52 Ticket 52]). -] - -In the following example the old and result value declarations use the specialization `contract::copy` so it is possible to access the old and result value of variables of type `num` even if `num` is non-copyable (see also [file example/contracts copy_inc.cpp]): - -[import ../example/contracts/copy_inc.cpp] -[copy_inc] -[copy_inc_call] - -Both calls `inc(i, j)` and `inc(n, m)` check all postconditions. -The first call copies the old and result values using `int`'s default copy constructor, the second call copies the old and result values using the copy operation implemented by the `contract::copy` specialization. - -[endsect] - -[section Pure Virtual Functions] - -It is possible to program contracts for pure virtual functions. -Pure virtual functions are specified with the usual `= 0;` symbol replacing the function definition just after the contract macros, for example (see also [file example/contracts pushable.hpp]): - -[import ../example/contracts/pushable.hpp] -[pushable] - -Furthermore, using the [macroref CONTRACT_MEMBER_BODY] macro, a derived class can be programmed without using the [macroref CONTRACT_CLASS] and [macroref CONTRACT_FUNCTION] macros even when the base class has pure virtual functions (see also [file example/contracts default_subcontracting_base.cpp]): - -[import ../example/contracts/default_subcontracting_base.cpp] -[default_subcontracting_base] - -This use of the [macroref CONTRACT_MEMBER_BODY] macro does not force programmers of derived classes to use the library macros [macroref CONTRACT_CLASS] and [macroref CONTRACT_FUNCTION] which would otherwise introduce the unusual library syntax in the derived class declaration. -However, in this case the derived class is forced to inherit the base class invariants, preconditions, and postconditions exactly as they are without the possibility to truly subcontract the base class (which is instead possible when the [macroref CONTRACT_CLASS] and [macroref CONTRACT_FUNCTION] macros are used in declaring the derived class). -[footnote -*Rationale.* -Older revisions of this library defined the macro `CONTRACT_MEMBER_BODY(class_type, function_name)` taking two parameters so this macro could not be used in declaring derived classes and the [macroref CONTRACT_CLASS] and [macroref CONTRACT_FUNCTION] macros where required when programming a class inheriting from a base class with contracts. -However, the authors prefer to leave the choice of programming full contracts for derived classes to the derived class programmers because of the unusual declaration syntax introduced by this library might not be necessary when derived classes do not need to alter the base's class contract. -] -Correctly, the derived class can never avoid checking the base class contracts neither when declared using the [macroref CONTRACT_CLASS] and [macroref CONTRACT_FUNCTION] macros, nor when declared using the [macroref CONTRACT_MEMBER_BODY] macro. - -[endsect] - -[section Subcontracting Preconditions] - -While subcontracting is theoretically sound and justified by the __substitution_principle__, in practise subcontracted preconditions might be confusing for programmers because of the implications of evaluating overriding preconditions in __logic_or__ with overridden preconditions (this is not the case for subcontracted postconditions and class invariants which usually behave as programmers expect because they are evaluated in __logic_and__). - -For example, consider the following base class `integer` which holds an integral value and its derived class `natural` which holds a natural (i.e., non-negative integer) value (see also [file example/contracts subcontract_pre_natural_failure.cpp]): - -[import ../example/contracts/subcontract_pre_natural_failure.cpp] -[subcontract_pre_natural_failure] - -From reading the contracts we conclude that: - -* `integer::get` returns the latest value set (as specified by `integer::set` postconditions). -* There is no constraint on the integer value that is passed to `integer::set` (because `integer::set` has no precondition). -* `natural::get` always returns a non-negative value (as specified by the `natural` class invariants). -* Only non-negative values can be passed to `natural::set` (as specified by `natural::set` preconditions). - -This last conclusion is incorrect! -Negative values can be passed to `natural::set` because they can be passed to its base virtual function `integral::set` (preconditions cannot only be weakened). -The complete set of `natural::set` preconditions is given by its base virtual function `integer::set` preconditions (which are always `true` because they are not specified) evaluated in __logic_or__ with the preconditions explicitly specified by `natural::set` (i.e., `value >= 0`): - - (true) or (value >= 0) - -Obviously, this always evaluates to `true` regardless of `value` being non-negative. -This is correct in accordance with the __substitution_principle__ for which `natural::set` can be called in any context where `integer::set` is called because `natural` inherits from `integer`. -Given that `integer::set` can be called regardless of `value` being non-negative (because it has no precondition) there is no precondition that we can later specify for `natural::set` that will change that and in fact `natural::set` can also be called with negative values without failing its subcontracted preconditions. -For example, the call: - -[subcontract_pre_natural_failure_call] - -Fails the class invariants checked while exiting `natural::set`: - -[pre -class invariant (on exit) number 1 "get() >= 0" failed: file "natural_subcontractpre.cpp", line 30 -] - -Ideally, this call would have failed much earlier at `natural::set` preconditions (in fact, the `natural::set` body is executed with the logically invalid negative value `-123` which could in general lead to catastrophic errors and mysterious bugs). - -The issue here is in the design. -A natural number is not an integer number because while it is valid to use an integer number in a context where it is assigned to a negative number, it is not valid to use a natural number in such a context so a natural number should not inherit from an integer number. -Inheritance models the [@http://en.wikipedia.org/wiki/Is-a /is-a/] relationship which should not be used in this case as the contracts and the __substitution_principle__ are telling us. - -[note -Note that if a virtual member function has no preconditions, it means that it is always valid to call it, and (in accordance with the __substitution_principle__) this semantic cannot be changed by the contracts of any overriding function no matter what preconditions we specify for it. -Similarly, if an overriding member function has no preconditions, it means that is is always valid to call it regardless of possible preconditions specified by any function that it overrides. -] - -An overriding function can specify `precondition( false )` if it wants to keep the same preconditions of the functions that is overriding. -A pure virtual function can specify `precondition( false )` to indicate that overriding functions will specify preconditions (this only makes sense for pure virtual functions because a function with `precondition( false )` can never be called successfully unless it is overridden and its preconditions are weakened, that might be acceptable for pure virtual because they must always be overridden). - -If programmers find subcontracted preconditions confusing, this library allows to forbid them by defining the configuration macro [macroref CONTRACT_CONFIG_DO_NOT_SUBCONTRACT_PRECONDITIONS]. -When this macro is defined, the library will generate a compile-time error if a derived class tries to override preconditions of member functions of any of its base classes (this is also the subcontracting behaviour specified by __N1962__). -However, note that in case of multiple-inheritance preconditions from the overridden function from all bases classes will always be checked in __logic_or__ with each other so preconditions from a base class could still be weaken by the preconditions of another base class even when the [macroref CONTRACT_CONFIG_DO_NOT_SUBCONTRACT_PRECONDITIONS] macro is defined. -By default the [macroref CONTRACT_CONFIG_DO_NOT_SUBCONTRACT_PRECONDITIONS] macro is not defined and this library allows to override preconditions (as specified by for __Eiffel__ by __Meyer97__ and in accordance with the __substitution_principle__). - -Another difference between subcontracted preconditions and subcontracted postconditions or class invariants is that subcontracted preconditions will always report a failure of the overridden preconditions. -For example, consider a set of base classes [^b['N]] and a derived class `d`: - - CONTRACT_CLASS( - struct (a) - ) { - ... // No member function `f`. - }; - - CONTRACT_CLASS( - struct (b``/N/``) - ) { - CONTRACT_CLASS_INVARIANT( ... ) - - CONTRACT_FUNCTION( - public virtual void (f) ( void ) // Overridden function. - precondition( ... ) - postcondition( ... ) - ) {} - - ... - }; - - CONTRACT_CLASS( - struct (c) - ) { - ... // No member function `f`. - }; - - CONTRACT_CLASS( - struct (d) extends( b1, a, b2, c, b3 ) - ) { - CONTRACT_CLASS_INVARIANT( ... ) - - CONTRACT_FUNCTION( - public virtual void (f) ( void ) // Overriding function. - precondition( ... ) - postcondition( ... ) - ) {} - - ... - }; - -When `d::f` is called, its subcontracted class invariants, postconditions, and preconditions are evaluated using the following expressions (the base classes `a` and `c` do not declare a virtual function `f` so they are automatically excluded from `d::f` subcontracting): - - b1::``/class-invariants/`` and b2::``/class-invariants/`` and b3::``/class-invariants/`` and d::``/class-invariants/`` // `d::f` subcontracted class invariants. - b1::f::``/postconditions/`` and b2::f::``/postconditions/`` and b3::f::``/postconditions/`` and d::f::``/postconditions/`` // `d::f` subcontracted postconditions. - b1::f::``/preconditions/`` or b2::f::``/preconditions/`` or b3::f::``/preconditions/`` or d::f::``/preconditions/`` // `d::f` subcontracted preconditions. - -When subcontracted class invariants or subcontracted postconditions fail, this library reports the first failed condition which can in general be in the base class contracts because they are checked first in the __logic_and__ chain (this can report a failure from any subcontracted class invariants [^b['N]::/class-invariants/] or [^d::/class-invariants/], and subcontracted postconditions [^b['N]::f::/postconditions/] or [^d::f::/postconditions/]). -However, when subcontracted preconditions fail it means that all overridden preconditions as well as the overriding preconditions have failed (because subcontracted preconditions are evaluated in __logic_or__). -In this case, this library will report the last evaluated failure which will always be in the overriding preconditions (always report a failure from [^d::f::/preconditions/]). -If programmers want instead the library to report the failure from the first overridden precondition that failed, they can define the configuration macro [macroref CONTRACT_CONFIG_REPORT_BASE_PRECONDITION_FAILURE] (always report a failure from [^b1::f::/preconditions/]). - -[endsect] - -[section Static Member Functions] - -It is possible to program contracts for static member functions. -Static member functions cannot access the object therefore their preconditions and postconditions also cannot access the object and they can only access other static members. -This library allows to specify a subset of class invariants called /static class invariants/ which do not access the object and that are checked at entry and exit of every constructor, destructor, and member functions even if static. -(Non-static class invariants are instead not checked at constructor entry, at destructor exit, and at entry and exit of static member functions because they require accessing the object, see also the __Contract_Programming_Overview__ section.) - -Static class invariants are empty (`void`) by default unless they are explicitly specified within the [macroref CONTRACT_CLASS_INVARIANT] macro using the following syntax: -[footnote -Static class invariants are not part of __N1962__ and they were first introduced by this library. -] - - static class( ``/assertion1/``, ``/assertion2/``, ... ) - -For example (see also [file example/contracts static_contract_instance_counter.cpp]): - -[import ../example/contracts/static_contract_instance_counter.cpp] -[static_contract_instance_counter] - -In this example there is only one static class invariant assertion `count() >= 0` and it is checked at entry and exit of every constructor, destructor, and member function including the static member function `count`. -If the static member function `count` had preconditions or postconditions, they would not be able to access the object (i.e., preconditions and postconditions will also be executed in static context). - -[endsect] - -[section Volatile Member Functions] - -It is possible to program contracts for volatile member functions. -Volatile member functions access the object as volatile therefore their preconditions and postconditions also access the object as volatile and can only access other volatile members. -This library allows to specify a different set of class invariants called /volatile class invariants/ which can only access the object as volatile and that are checked at entry and exit of every volatile member function. -(Constructors and destructors never access the object as volatile so volatile class invariants are not checked by constructors and destructors, see also the __Contract_Programming_Overview__ section.) - -Volatile class invariants are assumed to be the same as non-volatile class invariants unless they are explicitly specified within the [macroref CONTRACT_CLASS_INVARIANT] macro using the following syntax: -[footnote -Volatile class invariants are not part of __N1962__ and they were first introduced by this library. -It is not clear if there are real applications for volatile class invariants mainly because real applications of `volatile` itself are not clear in C++. -One very interesting use of `volatile` has been to [@http://www.drdobbs.com/cpp/184403766 avoid race conditions] in concurrent programming (but contracts are not useful for such an application of `volatile`). -] - - - volatile class( ``/assertion1/``, ``/assertion2/``, ... ) - -In most cases, it will be necessary to explicitly specify volatile class invariants when using volatile member functions (unless volatile overloads are provided for every member function that is used by the non-volatile class invariants). - -For example (see also [file example/contracts volatile_contract_shared_instance.cpp]): - -[import ../example/contracts/volatile_contract_shared_instance.cpp] -[volatile_contract_shared_instance] - -As usual, contracts are checked in constant-correct context therefore only `const volatile` members can be accessed from volatile class invariants, preconditions, and postconditions. - -[endsect] - -[section Operators] - -It is possible to program contracts for operators (both member function operators and free function operators). -The operator name must be specified using the following syntax when passed to the [macroref CONTRACT_FUNCTION], [macroref CONTRACT_FREE_BODY], and [macroref CONTRACT_MEMBER_BODY] macros: - - operator(``/symbol/``)(``/arbitrary-alphanumeric-name/``) - -The first parameter is the usual operator symbol (`==`, `+`, etc) the second parameter is an arbitrary but alphanumeric name (`equal`, `plus`, etc). -The operator `new`, the operator `delete`, and implicit type conversion operators for fundamental types containing no symbol can also be specified simply as: - - operator new - operator delete - operator ``/fundamental-type-without-symbols/`` - -The comma operator must be specified as: -[footnote -*Rationale.* -The comma operator cannot be specified using the comma symbol as in `operator(,)(my_comma_operator)` because the preprocessor uses commas to separate macro parameters so it is not possible to distinguish that from an implicit type conversion operator like `operator(std::vector)(std_vector)` (note that the operator name is arbitrary so it also cannot be used to distinguish these two cases). -] - - operator comma - -For example (see also [file example/contracts member_operator_string.cpp]): - -[import ../example/contracts/member_operator_string.cpp] -[member_operator_string] - -The memory operators `new`, `delete`, `new[]`, and `delete[]` must always be specified `static` when they are programmed as member function operators. -[footnote -*Rationale.* -C++ automatically promotes memory member operators to static members so the `static` keyword is optional for these member operators. -However, this library cannot inspect the operator symbol using the preprocessor to check if the operator is a memory member operator or not because the symbol contains non-alphanumeric tokens (which cannot be concatenated by the preprocessor). -Therefore, this library always requires memory member operators to be explicitly declared as static member functions. -] - -Free function operators are programmed using the same syntax for the operator names. - -[endsect] - -[section Nested Classes] - -It is possible to program contracts for nested classes noting that: - -# The access level `public`, `protected`, or `private` must be specified for contracted members and therefore also for nested classes. -# The `_TPL` macros must be used within templates so the [macroref CONTRACT_CLASS_TPL] macro needs to be used when programming a class nested within a class template. - -For example (see also [file example/contracts nested_class_bitset.cpp] and the __Concepts__ section): - -[import ../example/contracts/nested_class_bitset.cpp] -[nested_class_bitset] - -[endsect] - -[section Friends] - -It is possible to program contracts for friend classes and friend functions. -Classes can be declared friends and later contracted using the [macroref CONTRACT_CLASS] macro as usual: - - CONTRACT_CLASS( // Not even necessary to contract this class. - class (x) - ) { - CONTRACT_CLASS_INVARIANT( void ) - - friend class y ; - - // ... - }; - - CONTRACT_CLASS( - class (y) - ) { - CONTRACT_CLASS_INVARIANT( void ) - - // ... - }; - -Friend functions that are declared and defined within the enclosing class use the `friend` keyword within the [macroref CONTRACT_FUNCTION] macro (note that the access level `public`, `protected`, or `private` is optional in this case because these friend functions are not member functions). -Friend functions that are either forward declared friends or that are defined friends within the enclosing class, must use the [macroref CONTRACT_FREE_BODY] macro. -For example (see also [file example/contracts friend_counter.cpp]): - -[import ../example/contracts/friend_counter.cpp] -[friend_counter] - -The class enclosing the friend declarations might or might not be contracted. - -[endsect] - -[section Template Specializations] - -It is possible to program contracts for class template specializations. -The generic class template might or might not be contracted (see also [file example/contracts template_specializations_vector.cpp]): - -[import ../example/contracts/template_specializations_vector.cpp] -[template_specializations_vector] - -The template specialization types follow the class name as usual but they are wrapped within round parenthesis `( bool, Allocator )` instead than angular parenthesis `< bool, Allocator >` as in the following partial specialization: - -[template_specializations_vector_bool_allocator] - -The syntax `template( void )` must be used instead of `template< >` to indicate explicit specializations: - -[template_specializations_vector_bool] - -[endsect] - -[section Exception Specifications and Function-Try Blocks] - -It is possible to program exception specifications and function-try blocks for constructors, destructors, member functions, and free functions with contracts. -Exception specifications are part of the function declarations therefore they are programmed within the contract macros but the special syntax `throw( void )` must be used instead of `throw( )` to specify that no exception is thrown: - - throw( ``/exception-type1/``, ``/exception-type2/``, ... ) // As usual. - throw( void ) // Instead of `throw( )`. - -Function-try blocks are part of the function definition so they are normally programmed outside the contract macros. -However, for constructors with member initializers, the member initializers must be programmed within the [macroref CONTRACT_CONSTRUCTOR] macro and therefore also the function-try blocks must be programmed within the macro using the following syntax: - - try initialize( ``/initializer1/``, ``/initializer2/``, ... ) - catch(``/exception-declaration1/``) ( ``/instruction1/``; ``/instruction2/``; ... ) - catch(``/exception-declaration2/``) ( ``/instruction1/``; ``/instruction2/``; ... ) - catch(...) ( ``/instruction1/``; ``/instruction2/``; ... ) - -As usual, only one catch statement must be specified and the other catch statements are optional plus `catch(...)` can be used to catch all exceptions. -Note however that round parenthesis `( ... )` are used instead of curly parenthesis `{ ... }` to wrap the catch statement instructions (then the catch instructions are programmed with the usual syntax and separated by semicolons `;`). -(The maximum number of catch statements that can be programmed for constructor-try blocks is specified by the [macroref CONTRACT_LIMIT_CONSTRUCTOR_TRY_BLOCK_CATCHES] macro.) - -In the following example the constructor uses a function-try block to throw only `out_of_memory` and `error` exceptions while the destructor uses exception specifications to throw no exception (see also [file example/contracts exception_array.cpp]): - -[import ../example/contracts/exception_array.cpp] -[exception_array] - -(The `BOOST_IDENTITY_TYPE` macro can be used to wrap the catch statement exception declaration types if they contain unwrapped commas.) - -Exception specifications and function-try blocks apply only to exceptions thrown by the function body and not to exceptions thrown by the contracts themselves (if any) and by the contract checking code generated by this library macros. -[footnote -*Rationale.* -__N1962__ specifies that function-try blocks should only apply to the body code and not to the contract code. -No explicit requirement is stated in __N1962__ for exception specifications but the authors have decided to adopt the same requirement that applies to function-try blocks (because it seemed of little use for the contract to throw an exception just so it is handled by the exception specification). -] - -[endsect] - -[section Specifying Types (no Boost.Typeof)] - -This library uses __Boost_Typeof__ to automatically deduces postcondition old value types and constant assertion variable types. -If programmers do not want the library to use __Boost_Typeof__ they can explicitly specify these types. - -The types of postcondition old values are specified instead of using `auto` and they must be wrapped within round parenthesis unless they are fundamental types containing no symbol (these must match the type of the specified old-of expressions): - - (``/type/``) ``/variable/`` = CONTRACT_OLDOF ``/oldof-expression/`` - -The types of constant assertion variables are specified just before each variable name and they also must be wrapped within round parenthesis unless they are fundamental types containing no symbol: - - const( (``/type1/``) ``/variable1/``, (``/type2/``) ``/variable2/``, ... ) ``/boolean-expression/`` - -For example (see also [file example/contracts typed_counter.cpp]): - -[import ../example/contracts/typed_counter.cpp] -[typed_counter] - -Note that postcondition result values are always specified using `auto`: - - auto ``/result-variable/`` = return - -This is because the function return type is know by the library as specified in the function declaration within the [macroref CONTRACT_FUNCTION] macro. -Therefore, the postcondition result value type is never explicitly specified by programmers (but __Boost_Typeof__ is never used to deduce it). - -[note -It is recommended to not specify these types explicitly and let the library internally use __Boost_Typeof__ to deduce them because the library syntax is more readable without the explicit types. -However, all types must be properly registered with __Boost_Typeof__ as usual in order to use type-of emulation mode on __CXX03__ compilers that do not support native type-of (see __Boost_Typeof__ for more information). -] - -[endsect] - -[section Block Invariants and Loop Variants] - -/Block invariants/ can be used anywhere within the function body and they are used to assert correctness conditions of the implementation (very much like `assert`). -They are programmed specifying a list of assertions to the [macroref CONTRACT_BLOCK_INVARIANT] macro (including static, constant, and select assertions): - - CONTRACT_BLOCK_INVARIANT( ``/assertion1/``, ``/assertion2/``, ... ) - -When block invariants are used within a loop, they are also called /loop invariants/ (e.g., __Eiffel__ uses this terminology). - -Furthermore, this library allows to specify [@http://en.wikipedia.org/wiki/Loop_variant ['loop variants]]. -A loop variant is a non-negative monotonically decreasing number that is updated at each iteration of the loop. -The specified loop variant expression is calculated by this library at each iteration of the loop and it is automatically asserted to be non-negative (`>= 0`) and to decrease monotonically from the previous loop iteration. -Because the loop variant monotonically decreases and it cannot be smaller than zero, either the loop terminates or one of the two library assertions will eventually fail in which case the library will call the [funcref contract::loop_variant_broken] handler therefore detecting and stopping infinite loops. -Each given loop can only have one variant which is specified using the [macroref CONTRACT_LOOP_VARIANT] macro. -The enclosing loop (`while`, `for`, `do`, etc) must be declared using the [macroref CONTRACT_LOOP] macro: - - CONTRACT_LOOP( ``/loop-declaration/`` ) { - CONTRACT_LOOP_VARIANT( ``/non-negative-monotonically-decreasing-expression/`` ) - ... + if(!``[^['boolean-condition]]``) { + throw boost::contract::assertion_failure(__FILE__, __LINE__, + BOOST_PP_STRINGIZE(``[^['boolean-condition]]``)); } -Note that the library cannot automatically make constant any of the variables within the function body therefore constant block invariant assertions and constant loop variant expressions should be used by programmers if they want to enforce constant-correctness for block invariants and loop variants. +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_failed], [funcref boost::contract::postcondition_failed], [funcref boost::contract::entry_invariant_failed] or [funcref boost::contract::exit_invariant_failed]). +In fact, if there is a need for it, programmers can always program contract assertions that throw user-defined exceptions without using [macroref BOOST_CONTRACT_ASSERT] (see also __Throw_on_Failure__): -The following example uses a loop to calculate the [@http://en.wikipedia.org/wiki/Greatest_common_divisor Greatest Common Divisor (GCD)] of two integral numbers (see also [file example/contracts blockinv_loopvar_gcd.cpp]): + if(!``[^['boolean-condition]]``) throw ``[^['user-defined-exception]]``(...); -[import ../example/contracts/blockinv_loopvar_gcd.cpp] -[blockinv_loopvar_gcd] +[heading Base Types (Variadic)] -__Eiffel__ supports loop variants but __N1962__ does not. -Loop variants might not be very useful especially if __Boost_Foreach__ or similar constructs are used to ensure loop termination. +As shown in __Base_Types__, this library provides the [macroref BOOST_CONTRACT_BASE_TYPES] variadic macro to declare a `base_types` member type that lists the 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 (see also [@../../example/features/no_macros.cpp =no_macros.cpp=]): -[endsect] +[no_base_types_macro] -[section Contract Broken Handlers (Throw on Failure)] - -When a contract assertion fails, this library prints a message on the standard error `std::cerr` and it terminates the program calling `std::terminate`. -Programmers can change this behavior customizing the actions that the library takes on contract assertion failure by setting the contract broken handler functions. -By default the library terminates the program because a contract failure indicates that the program is in an invalid state that programmers specified it should never happen (so the only sensible assumption is that the program execution should not continue). -However, in some cases programmers might need to handle even such catastrophic failures by executing some fail-safe code instead of terminating the program and that can be done customizing the contract broken handlers. - -The library functions [funcref contract::set_precondition_broken], [funcref contract::set_postcondition_broken], [funcref contract::set_class_invariant_broken], [funcref contract::set_block_invariant_broken], and [funcref contract::set_loop_variant_broken] can be used to customize the action to taken in case of precondition, postcondition, class invariant, block invariant, and loop variant failure respectively. -Furthermore, class invariants are checked at entry, at normal exit, and at exit but when exceptions are thrown so more granular handlers can be set for each of these cases using [funcref contract::set_class_invariant_broken_on_entry], [funcref contract::set_class_invariant_broken_on_exit], and [funcref contract::set_class_invariant_broken_on_throw] (using [funcref contract::set_class_invariant_broken] is equivalent to setting all these class invariant broken handles to the same handler). -[footnote -__N1962__ does not allow to configure class invariant broken handlers differently for entry, exit, and throw. -] - -This library passes a parameter of type [enumref contract::from] to the contract broken handler functions indicating the context that failed the contract assertion (e.g., this parameter will be set to `contract::FROM_DESTRUCTOR` if the contract assertion failed from a destructor): -[footnote -The `contract::from` parameter was not part of __N1962__ contract broken handlers but the proposal hinted that it might be needed (need that was confirmed by the implementation of this library). -] - - void ``/contract-broken-handler/`` ( contract::from const& context ) - -[important -In order to comply with the STL exception safety requirements, destructors should never throw. -Therefore, even if programmers customize the contract broken handlers to throw exceptions instead of terminating, the handlers should never throw when contract assertions fail from a destructor (and the [enumref contract::from] parameter can be used to discriminate this case). -] - -The contract broken handlers are always invoked with an active exception that refers to the exception that failed the contract: +The `base_types` member type must be a `boost::mpl::vector` listing /only/ `public` base classes (because only public bases subcontract, see also __Function_Calls__). [footnote *Rationale.* -Exceptions are used to signal a contract assertion failure because it is not possible to directly call the contract broken handler ([funcref contract::precondition_broken], etc) instead of throwing the exception in oder to properly implement subcontracting. -For example, if an overriding precondition fails but the overridden precondition is true then the library will not call the broken handler even if the overriding precondition threw an exception (as required by subcontracting). -Contract assertion failures are critical error conditions so it is actually natural that the library uses exceptions to signal them (note that the library will always handle the exceptions by calling the contract broken handlers which terminate the program by default so the fact that the library signals contract assertion failures using exceptions does not imply that an exception will be thrown if a contract assertion fails, that is entirely decided by the implementation of the broken handlers). +`boost::mpl::vector` is used because this library is design to work with other Boost libraries. ] +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. -# Either an exception that was explicitly thrown by the user from the contract (e.g. `not_a_number` in the example blow). -# Or, an exception that was thrown ["behind the scene] while evaluating a contract assertion (e.g., the assertion calls an STL algorithm and that throws `std::bad_alloc`). -# Or, an exception automatically thrown by this library in case a contract assertion is evaluated to be false (these exceptions are always [classref contract::broken] objects and they contained detailed information about the contract assertion that was evaluated to be false: file name, line number, assertion number, and assertion code). +[heading Old Values (Variadic)] + +As shown in __Old_Values__ and __Virtual_Public_Functions__, this library provides the [macroref BOOST_CONTRACT_OLDOF] variadic macro to initialize old values. +Programmers can also initialize old values without using [macroref BOOST_CONTRACT_OLDOF] at the cost of writing a bit more code manually (see also [@../../example/features/no_macros.cpp =no_macros.cpp=]): + +[no_oldof_macro] + +C++ ternary operator `... ? ... : ...` must be used here to avoid evaluating and copying the old value expression (`size()` in this example) when old values are not being copied (because postcondition checking is disabled, within overridden virtual function calls for subcontracting, etc.). +[classref boost::contract::old]`()` creates an empty old value (that introduces no copy). +[funcref boost::contract::copy_old]`()` returns `true` if and only if old values are being copied. +When used in public virtual functions, programmers must pass the extra [classref boost::contract::virtual_]`* v` argument to [funcref boost::contract::copy_old]`(v)`, for example (see also [@../../example/features/no_macros.cpp =no_macros.cpp=]): + +[no_virtual_oldof_macro] + +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 illustrates how to use this library without C++11 lambda functions. +This presets some advantages: + +* It allows to use this library on compilers that do not support C++11 lambda functions (essentially C++03 compilers can be used, see __No_Macros__ to also avoid using variadic macros). +* Functors can be programmed to fully enforce constant-correctness and other contract requirements at compile-time (see also __Constant_Correctness__). [footnote -The assertion number is meaningful only within a specific handler. -For example, if assertion number `2` failed within the class invariant broken handler that mean that the class invariant number `2` failed. -Therefore, the assertion number is not useful if a single handler is programmed for all types of contracts because such an handler can no longer distinguish between class invariants, preconditions, postconditions, etc. +If C++ supported to capture lambda function variables by constant references `[const&] () { ... }` that could be used to program contract functors using lambda functions that also enforce __Constant_Correctness__ at compile-time (not that value captures cannot be used to program postconditions, plus it introduces an extra copy that might not always be possible or desirable). ] +* Contracts are automatically separated from function body implementations (see also __Specification_and_Implementation__ and __Separate_Body_Implementation__). -In all these cases the contract assertion is considered failed because it was not evaluated to be true (and that is the case not only for assertions that are evaluated to be false but also for assertions that throw exceptions while being evaluated). +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 functors (therefore, the authors think this library is most useful when C++11 lambda functions can be used). + +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__): + +* In general, precondition and postcondition functions (e.g., named `..._precondition` and `..._postcondition`) should take their arguments by `const&` and they should be either `static` or `const` member functions. +However, postconditions can (but do not have to) take old value arguments by value (because these are pointers to `const` objects already). +* In general, old value functions (e.g., named `..._old`) 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 allowed 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 illustrated by __Separate_Body_Implementation__). [footnote -*Rationale.* -Threating an exception thrown while evaluating an assertion as a failure of the contract assertion is a clear policy established by this library under the principle that a contract assertion fails unless it is evaluated to be true. -__N1962__ does not completely clarify this point. -] -The customized contract broken handlers can re-throw the active exception and catch it so to inspect it for logging or for any other customized behaviour that might need to be implemented by the programmers. - -The following example customizes the contract broken handlers to throw exceptions (both user-defined exceptions like `not_a_number` and the [classref contract::broken] exception that the library automatically throws in case of a contract assertion failure). -However, the customized handlers never throw from within a destructor to comply with STL exception safety requirements (see also [file example/contracts broken_handler_sqrt.cpp]): -[footnote -In this example, contract failures from destructors are logged and then simply ignored. -That might be acceptable in this simple example but it is probably a very bad idea in general. +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. ] -[import ../example/contracts/broken_handler_sqrt.cpp] -[broken_handler_sqrt] - -Note how the ternary operator `:?` can be used to program assertions that throw exceptions on failure: - - x >= 0.0 ? true : throw not_a_number - -Then the contract broken handlers are customized to propagate the exceptions instead of handling them by calling `std::terminate` (default behaviour). - -See also [file example/contracts contract_failure.cpp] for a more complex example that redefines the contract broken handlers to throw exceptions in order to automatically check that the correct contract broken handlers are called when assertions fail in accordance with the call semantics explained in the __Contract_Programming_Overview__ section. +Finally, note that the extra 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__). [endsect] diff --git a/doc/qbk/concepts.qbk b/doc/qbk/concepts.qbk deleted file mode 100644 index dbd880c..0000000 --- a/doc/qbk/concepts.qbk +++ /dev/null @@ -1,219 +0,0 @@ - -[/ Copyright (C) 2008-2012 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) ] -[/ Home at http://sourceforge.net/projects/contractpp ] - -[section Concepts] - -This section explains how to use this library to check concepts. -Concepts are part of the program specifications because they enforce requirements on generic types at compile-time and therefore they are within the scope of this library. - -Concepts were proposed for addition to __CXX11__ but they were unfortunately never adopted (see __N2081__). -The concepts that are checked using this library need to be defined using the __Boost_ConceptCheck__ library. -This library does not add any extra functionality with respect to the concept checking features already provided by __Boost_ConceptCheck__ but it allows to specify both concepts and contracts together within a unified syntax. - -[section Class Templates] - -It is possible to list the concepts to check for class templates using `requires` within the [macroref CONTRACT_CLASS] macro, after the template parameter declarations (see also the __Grammar__ section): - - template( ``/template-parameter1/``, ``/template-parameter2/``, ... ) requires( ``/concept1/``, ``/concept2/``, ... ) - -The following example requires that the generic type `T` specified for the class template `vector` is always __CopyConstructible__ and it uses the `boost::CopyConstructible` concept defined by __Boost_ConceptCheck__ (see also [file example/concepts class_member_concept_vector.hpp], [file example/concepts class_member_concept_vector_error.cpp], and [file example/concepts class_member_concept_vector.cpp]): - -[import ../example/concepts/class_member_concept_vector.hpp] -[class_member_concept_vector_class] - -If the class template `vector` is instantiated on a type `T` that is not __CopyConstructible__, the compiler will generate an error (with the usual format of __Boost_ConceptCheck__ errors). - -[endsect] - -[section Function Templates] - -It is possible to list concepts to check for function templates using `requires` within the [macroref CONTRACT_FUNCTION] macro, after the template parameter declarations (see also the __Grammar__ section). - -For example, for a constructor function template (see also [file example/concepts class_member_concept_vector.hpp], [file example/concepts class_member_concept_vector_constructor_error.cpp], and [file example/concepts class_member_concept_vector.cpp]): - -[class_member_concept_vector_constructor] - -And, for a member function template (see also [file example/concepts class_member_concept_vector.hpp], [file example/concepts class_member_concept_vector_member_error.cpp], and [file example/concepts class_member_concept_vector.cpp]): - -[class_member_concept_vector_member] - -If the `vector` constructor template or the `vector::insert` member function template are instantiated on a type `Iterator` that is not an __InputIterator__, the compiler will generate an error (with the usual format of __Boost_ConceptCheck__ errors). - -So far we have used concepts that are predefined by __Boost_ConceptCheck__ but it is also possible to check user-defined concepts as long as they are defined using __Boost_ConceptCheck__. -For example, consider the following user-defined `Addable` concept (see also [file example/concepts free_concept_operator_preinc.hpp], [file example/concepts free_concept_operator_preinc_error.cpp], and [file example/concepts free_concept_operator_preinc.cpp]): - -[import ../example/concepts/free_concept_operator_preinc.hpp] -[free_concept_operator_preinc] - -If this templated operator `++` is instantiated on a type `T` that is not __Assignable__ or not `Addable`, the compiler will generate an error (with the usual format of __Boost_ConceptCheck__ error). - -Note that concepts can also be specified for free function templates, for free operator templates, and for member operator templates (as illustrated in some of the above examples). - -[endsect] - -[section Concept Definitions (Not Implemented)] - -Using the preprocessor parsing techniques introduced by the library, it should be possible to implement the following syntax to define [@http://en.wikipedia.org/wiki/Concepts_(C%2B%2B) concepts]. -Note how this syntax resembles the syntax proposed by __N2081__ for adding concepts to __CXX11__ (__N2081__ and concepts were unfortunately not adopted by the standard committee). - - CONTRACT_CONCEPT( // A concept definition. - auto concept (LessThanComparable) ( typename T ) - ( - bool operator(<)(less) ( T , T ) - ) - ) - - CONTRACT_CONCEPT( // Concepts with multiple parameters. - auto concept (Convertible) ( typename T, typename U ) - ( - operator(U)(U_type) ( T const& ) - ) - ) - - CONTRACT_CONCEPT( // Concept composition. - concept (InputIterator) ( typename Iterator, typename Value ) - ( - requires Regular, - - (Value) operator(*)(deref) ( Iterator const& ), - (Iterator&) operator(++)(preinc) ( Iterator& ), - (Iterator) operator(++)(postinc) ( Iterator&, int ) - ) - ) - - CONTRACT_CONCEPT( // Derived concepts. - concept (ForwardIterator) ( typename Iterator, typename Value ) - extends( InputIterator ) - ( - // Other requirements here... - ) - ) - - CONTRACT_CONCEPT( // Typenames within concepts. - concept (InputIterator) ( typename Iterator ) - ( - typename value_type, - typename reference, - typename pointer, - typename difference_type, - - requires Regular, - requires (Convertible), - - (reference) operator(*)(deref) ( const Iterator& ), - (Iterator&) operator(++)(preinc) ( Iterator& ), - (Iterator) operator(++)(postinc) ( Iterator&, int ) - ) - ) - - CONTRACT_CONCEPT( // Concept maps. - concept_map (InputIterator) - ( - typedef char value_type, - typedef (char&) reference, - typedef (char*) pointer, - typedef ptrdiff_t difference_type - ) - ) - - CONTRACT_CONCEPT( // Concept maps can be templated. - template( typename T ) - concept_map (InputIterator) ( T* ) - ( - typedef (T&) value_type, - typedef (T&) reference, - typedef (T*) pointer, - typedef ptrdiff_t difference_type - ) - ) - - CONTRACT_CONCEPT( // Concept maps as mini-types. - concept (Stack) ( typename X ) - ( - typename value_type, - - void (push) ( X&, value_type const& ), - void (pop) ( X& ), - (value_type) (top) ( X const& ), - bool (empty) ( X const& ) - ) - ) - - CONTRACT_CONCEPT( // Concept maps as mini-types (specializations). - template( typename T ) - concept_map (Stack) ( std::vector ) - ( - typedef (T) value_type, - - void (push) ( (std::vector&) v, (T const&) x ) - ( - v.push_back(x); - ), - - void (pop) ( (std::vector&) v ) - ( - v.pop_back(); - ), - - (T) (top) ( (std::vector const&) v ) - ( - return v.back(); - ), - - bool (empty) ( (std::vector const&) v ) - ( - return v.emtpy(); - ) - ) - ) - - CONTRACT_CONCEPT( // Axioms. - concept (Semigroup) ( typename Op, typename T ) - extends( CopyConstructible ) - ( - (T) operator(())(call) ( Op, T, T ), - - axiom (Associativity) ( (Op) op, (T) x, (T) y, (T) z ) - ( - op(x, op(y, z)) == op(op(x, y), z); - ) - ) - ) - -Note that: - -# Parenthesis around function parameter types can be always allowed but they should be required only when the parameter name is also specified. -# The function bodies need to be specified within the macros and that will make compiler errors very hard to use (because the errors will all refer to the same line number, the line number on which the `CONTRACT_CONCEPT` macro expanded). -However, concept definitions, including possible function bodies, might be simple enough for this not to be a major issue at least in the most common cases (the authors do not have enough experience with programming concept definitions to truly assess this). - -The authors /think/ this syntax can be implemented and parsed using the preprocessor however the authors have not tried to implement this yet. -If this syntax can indeed be implemented, it should then be investigated if the actual concept definitions can be programmed from the parsed concept traits using C++ (this seems possible at least for __CXX11__ based on some work done for the [@http://zao.se/~zao/boostcon/11/slides/Boost.Generic.pdf Generic] library). - -The authors recognize that implementing concept definitions would be a nice addition to this library (again, concepts are parts of the program specifications, they are contracts on the type system that are checked at compile-time, so both concept checking and concept definition are within the scope of this library). -However, at the moment there are no concrete plans for extending this library with the concept definitions (see also [@https://sourceforge.net/apps/trac/contractpp/ticket/49 Ticket 49]). - -The following is a side-by-side comparison of this possible concept definition syntax with the syntax proposed by __N2081__: - -[import ../example/concepts/concept_def.cpp] -[import ../example/concepts/concept_def_npaper.cpp] -[table -[ [Possible Extension of This Library (not implemented)] [\[N2081\] Proposal (not part of C++)] ] -[ [[concept_def]] [[concept_def_npaper]] ] -] - -Note that: - -# Extra wrapping parenthesis are used when expressions contain unwrapped commas `,` or leading symbols. -# The specifiers `constructor`, `destructor`, and `member` follow the same syntax as the [macroref CONTRACT_CONSTRUCTOR_BODY] and [macroref CONTRACT_DESTRUCTOR_BODY], and they serve a purpose similar to these macros in naming the constructors, destructors, and member functions outside class declarations. - -If concept definitions were added to this library, concepts would still be checked using the `requires` specifier in class and function declarations as we have seen so far (it might even be possible for concepts defines using __Boost_ConceptCheck__ to be still specified using some type tagging of this library concept types to internally distinguish between __Boost_ConceptCheck__ concepts and concepts define using this library). -Furthermore, this library could provide all the standard concepts defined in __N2914__ in an header file =contract/std/concept.hpp=. - -[endsect] - -[endsect] - diff --git a/doc/qbk/contract.qbk b/doc/qbk/contract.qbk index 89154a9..fb88079 100644 --- a/doc/qbk/contract.qbk +++ b/doc/qbk/contract.qbk @@ -116,19 +116,12 @@ Its methodology was first introduced by the __Eiffel__ programming language (see for the C++ programming language. All Contract Programming features are supported: subcontracting, class invariants, postconditions (with old and result values), preconditions, customizable actions on assertion failure, optional assertion compilation, disable assertion checking within other assertion checking, etc. -Consult this documentation in [@index.html HTML] or [@contract.pdf PDF] format. - [include introduction.qbk] [include getting_started.qbk] [include contract_programming_overview.qbk] [include tutorial.qbk] [include advanced_topics.qbk] -[include virtual_specifiers.qbk] -[include concepts.qbk] -[include named_parameters.qbk] -[/ include examples.qbk] -[include grammar.qbk] -[include no_variadic_macros.qbk] +[include examples.qbk] [/ xinclude reference.xml] [include release_notes.qbk] [include bibliography.qbk] diff --git a/doc/qbk/examples.qbk b/doc/qbk/examples.qbk index ac55374..d054a40 100644 --- a/doc/qbk/examples.qbk +++ b/doc/qbk/examples.qbk @@ -1,318 +1,140 @@ -[/ Copyright (C) 2008-2012 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) ] -[/ Home at http://sourceforge.net/projects/contractpp ] - [section Examples] -This section lists non-trivial examples programmed using this library. -The listed examples are taken from the foloowing sources (which are referenced in the title of each example). +This section lists a few non-trivial examples taken from different Contract Programming sources and re-implemented using this library. -[table -[ [Sources] [Notes] ] -[ [__N1962__] [ -Examples from the proposal to add Contract Programming to __CXX11__ submitted to the standard committee (unfortunately, this proposal was never accepted into the standard). -] ] -[ [__N2081__] [ -Examples from the proposal to add concepts to __CXX11__ submitted to the standard committee (unfortunately, this proposal was never accepted into the standard). -These examples have been extended to specify both concepts and contracts. -] ] -[ [__Meyer97__ __Mitchell02__] [ -Examples using the __Eiffel__ programming language and reprogrammed using this library for C++. -] ] -[ [__Cline90__] [ -Examples from a very early proposal called Annotated C++ (A++) to add Contract Programming to C++ (A++ was never implemented or proposed for addition to the standard). -] ] -[ [__Stroustrup97__] [ -One example that shows the importance of class invariants and how to configure this library to throw exceptions instead of terminating the program when contracts are broken. -] ] -] +Some of these examples might be from old sources, containing old or obsolete code practices, not be optimized for execution speed, and they be more relevant in the context of programming languages different from C++ (e.g., Eiffel or D). +Nevertheless, programmers are encouraged to review these examples to see a few different applications of this library that could be useful in practice. -The followings are among the most interesting examples: +Sources: -[table -[ [Key Example] [Topic] ] -[ [[link contract__.examples.__n1962___vector__comparison_with_c___proposed_syntax \[N1962\] Vector]] [ -A comparison between this library syntax and the syntax for contract and concept checking proposed by __N1962__ and __N2081__ respectively. -] ] -[ [[link contract__.examples.__n2081___add__generic_addition_algorithm \[N2081\] Add]] [ -Contracts and user-defined concepts. -] ] -[ [[link contract__.examples.__mitchell02___counter__subcontracting_and_virtual_specifiers__final__override__new__and_pure_virtual_ \[Mitchell02\] Counter]] [ -Subcontracting and __CXX11__-like virtual specifiers `final`, `override`, `new`, and pure virtual. -] ] -[ [[link contract__.examples.__meyer97___stack4__comparison_with_eiffel_syntax \[Meyer97\] Stack4]] [ -A comparison between this library and __Eiffel__ syntax for preconditions, postconditions, and class invariants. -] ] -[ [[link contract__.examples.__meyer97___gcd__loop_variants_and_invariants_plus_comparison_with_eiffel_syntax \[Meyer97\] GCD]] [ -A comparison between this library and __Eiffel__ syntax for loop variants and block invariants. -] ] -[ [[link contract__.examples.__cline90___vector__comparison_with_a___proposed_syntax \[Cline90\] Vector]] [ -A comparison between this library and A++ syntax. -] ] -] +* __N1962__: Examples from the proposal to add Contract Programming to C++11 (unfortunately, this proposal was never accepted into the standard). +* __Meyer97__: Examples using the Eiffel programming language and reprogrammed using this library for C++. +* __Mitchell02__: Additional examples using the Eiffel programming language and reprogrammed using this library for C++. +* __Cline90__: Examples from a very early proposal called Annotated C++ (A++) to add Contract Programming to C++ (A++ was never implemented or proposed for addition to the standard). +* __Stroustrup97__: One example that shows the importance of class invariants and how to configure this library to throw exceptions instead of terminating the program on contract failure. -[section \[N1962\] Vector: Comparison with C++ proposed syntax] -[import ../example/n1962/vector.hpp] +Most interesting examples: + +* [link contract__.examples.__n1962___vector__comparison_with_c___proposed_syntax \[N1962\] Vector]: The complete contracts of `std::vector` and a comparison with __N1962__ syntax. +* [link contract__.examples.__n1962___square_root__default_parameters_and_comparison_with_d_syntax \[N1962\] Square Root]: A comparison with D syntax. +* [link contract__.examples.__mitchell02___counter__subcontracting_and_virtual_specifiers__final__override__new__and_pure_virtual_ \[Mitchell02\] Counter]: Subcontracting. +* [link contract__.examples.__meyer97___stack4__comparison_with_eiffel_syntax \[Meyer97\] Stack4]: A comparison with Eiffel syntax. +* [link contract__.examples.__cline90___vector__comparison_with_a___proposed_syntax \[Cline90\] Vector]: A comparison with A++ syntax. + +[heading \[N1962\] Vector: Comparison with C++ proposal's syntax] [import ../example/n1962/vector.cpp] -[import ../example/n1962/vector_npaper.hpp] +[import ../example/n1962/vector_n1962.hpp] [table - [ [This Library (C++03)] [\[N1962\] and \[N2081\] Proposals (not part of C++)] ] - [ [[n1962_vector]] [[n1962_vector_npaper]] ] - [ [[n1962_vector_main]] [] ] + [ [This Library] [\[N1962\] Proposal (not part of C++)] ] + [ [[n1962_vector]] [[n1962_vector_n1962]] ] ] -[endsect] -[section \[N1962\] Circle: Subcontracting] +[heading \[N1962\] Circle: Subcontracting] [import ../example/n1962/circle.cpp] [n1962_circle] -[endsect] -[section \[N1962\] Factorial: Recursion and assertion computational complexity] +[heading \[N1962\] Factorial: Recursion and assertion computational complexity] [import ../example/n1962/factorial.cpp] [n1962_factorial] -[endsect] -[section \[N1962\] Equal: Operators] -[import ../example/n1962/equal.hpp] -[n1962_equal_header] -[import ../example/n1962/equal_not.hpp] -[n1962_equal_not_header] -[import ../example/n1962/equal_main.cpp] -[n1962_equal_main] -[endsect] +[heading \[N1962\] Equal: Operators] +[import ../example/n1962/equal.cpp] +[n1962_equal] -[section \[N1962\] Sum: Separated body definitions] -[import ../example/n1962/sum.hpp] -[n1962_sum_header] +[heading \[N1962\] Sum: Array parameter] [import ../example/n1962/sum.cpp] [n1962_sum] -[import ../example/n1962/sum_main.cpp] -[n1962_sum_main] -[endsect] -[section \[N1962\] Square Root: Default parameters and comparison with D syntax] +[heading \[N1962\] Square Root: Default parameters and comparison with D syntax] [import ../example/n1962/sqrt.cpp] [import ../example/n1962/sqrt.d] [table - [ [This Library (C++03)] [The D Programming Language] ] + [ [This Library] [The D Programming Language] ] [ [[n1962_sqrt]] [[n1962_sqrt_d]] ] ] -[endsect] -[section \[N1962\] Block: Block invariants] -[import ../example/n1962/block_invariant.cpp] -[n1962_block_invariant] -[endsect] - -[section \[N2081\] Add: Generic addition algorithm] -[import ../example/n2081/add.hpp] -[n2081_add_header] -[import ../example/n2081/add.cpp] -[n2081_add] -[import ../example/n2081/add_error.cpp] -[n2081_add_error] -[endsect] - -[section \[N2081\] Advance: Concept-based iterator overloading (emulated using tags)] -[import ../example/n2081/advance.cpp] -[n2081_advance] -[endsect] - -[section \[N2081\] Find: Generic find algorithm] -[import ../example/n2081/find.hpp] -[n2081_find_header] -[import ../example/n2081/find.cpp] -[n2081_find] -[import ../example/n2081/find_error.cpp] -[n2081_find_error] -[endsect] - -[section \[N2081\] Apply: Overloaded invocation of functors] -[import ../example/n2081/apply.cpp] -[n2081_apply] -[endsect] - -[section \[N2081\] For Each: Generic for-each algorithm] -[import ../example/n2081/for_each.cpp] -[n2081_for_each] -[endsect] - -[section \[N2081\] Transform: Generic binary transformation algorithm] -[import ../example/n2081/transform.cpp] -[n2081_transform] -[endsect] - -[section \[N2081\] Count: Generic counting algorithm] -[import ../example/n2081/count.cpp] -[n2081_count] -[endsect] - -[section \[N2081\] Convert: Conversion between two types] -[import ../example/n2081/convert.hpp] -[n2081_convert_header] -[import ../example/n2081/convert.cpp] -[n2081_convert] -[import ../example/n2081/convert_error.cpp] -[n2081_convert_error] -[endsect] - -[section \[N2081\] Equal: Generic equality comparison] -[import ../example/n2081/equal.hpp] -[n2081_equal_header] -[import ../example/n2081/equal.cpp] -[n2081_equal] -[import ../example/n2081/equal_error.cpp] -[n2081_equal_error] -[endsect] - -[section \[N2081\] Less Equal: Generic less-than or equal-to comparison] -[import ../example/n2081/less_eq.cpp] -[n2081_less_eq] -[endsect] - -[section \[N2081\] De-Ref: Generic iterator dereferencing] -[import ../example/n2081/deref.cpp] -[n2081_deref] -[endsect] - -[section \[N2081\] Min: Generic minimum algorithm] -[import ../example/n2081/min.hpp] -[n2081_min_header] -[import ../example/n2081/min.cpp] -[n2081_min] -[import ../example/n2081/min_error.cpp] -[n2081_min_error] -[endsect] - -[section \[Meyer97\] Stack4: Comparison with Eiffel syntax] +[heading \[Meyer97\] Stack4: Comparison with Eiffel syntax] [import ../example/meyer97/stack4.hpp] [import ../example/meyer97/stack4_main.cpp] [import ../example/meyer97/stack4.e] [table - [ [This Library (C++03)] [The Eiffel Programming Language] ] + [ [This Library] [The Eiffel Programming Language] ] [ [[meyer97_stack4_header]] [[meyer97_stack4_e]] ] [ [[meyer97_stack4_main]] [] ] ] -[endsect] -[section \[Meyer97\] Stack3: Error codes instead of preconditions] +[heading \[Meyer97\] Stack3: Error codes instead of preconditions] [import ../example/meyer97/stack3.cpp] [meyer97_stack3] -[endsect] -[section \[Meyer97\] GCD: Loop variants and invariants plus comparison with Eiffel syntax] -[import ../example/meyer97/gcd.cpp] -[import ../example/meyer97/gcd.e] -[table - [ [This Library (C++03)] [The Eiffel Programming Language] ] - [ [[meyer97_gcd]] [[teletype] [meyer97_gcd_e] [c++]] ] -] -[endsect] - -[section \[Meyer97\] Max-Array: Nested loop variants and invariants] -[import ../example/meyer97/maxarray.cpp] -[meyer97_maxarray] -[endsect] - -[section \[Mitchell02\] Name List: Relaxed subcontracts] -[import ../example/mitchell02/name_list.hpp] -[mitchell02_name_list_header] +[heading \[Mitchell02\] Name List: Relaxing subcontracts] [import ../example/mitchell02/name_list.cpp] [mitchell02_name_list] -[import ../example/mitchell02/name_list_main.cpp] -[mitchell02_name_list_main] -[endsect] -[section \[Mitchell02\] Dictionary: Simple key-value map] +[heading \[Mitchell02\] Dictionary: Key-value map] [import ../example/mitchell02/dictionary.cpp] [mitchell02_dictionary] -[endsect] -[section \[Mitchell02\] Courier: Subcontracting and static class invariants] -[import ../example/mitchell02/courier.hpp] -[mitchell02_courier_header] +[heading \[Mitchell02\] Courier: Subcontracting and static class invariants] [import ../example/mitchell02/courier.cpp] [mitchell02_courier] -[import ../example/mitchell02/courier_main.cpp] -[mitchell02_courier_main] -[endsect] -[section \[Mitchell02\] Stack: Simple stack dispenser] +[heading \[Mitchell02\] Stack: Stack-like container] [import ../example/mitchell02/stack.cpp] [mitchell02_stack] -[endsect] -[section \[Mitchell02\] Simple Queue: Simple queue dispenser] +[heading \[Mitchell02\] Simple Queue: Queue-like container] [import ../example/mitchell02/simple_queue.cpp] [mitchell02_simple_queue] -[endsect] -[section \[Mitchell02\] Customer Manager: Contracts instead of Defensive Programming] -[import ../example/mitchell02/customer_manager.hpp] -[mitchell02_customer_manager_header] +[heading \[Mitchell02\] Customer Manager: Contracts instead of Defensive Programming] [import ../example/mitchell02/customer_manager.cpp] [mitchell02_customer_manager] -[import ../example/mitchell02/customer_manager_main.cpp] -[mitchell02_customer_manager_main] -[endsect] -[section \[Mitchell02\] Observer: Contracts for pure virtual functions] +[heading \[Mitchell02\] Observer: Pure virtual functions] [import ../example/mitchell02/observer/observer.hpp] -[mitchell02_observer_header] +[mitchell02_observer] [import ../example/mitchell02/observer/subject.hpp] -[mitchell02_subject_header] +[mitchell02_subject] [import ../example/mitchell02/observer_main.cpp] [mitchell02_observer_main] -[endsect] -[section \[Mitchell02\] Counter: Subcontracting and virtual specifiers (final, override, new, and pure virtual)] +[heading \[Mitchell02\] Counter: Subcontracting] [import ../example/mitchell02/counter/push_button.hpp] -[mitchell02_push_button_header] +[mitchell02_push_button] [import ../example/mitchell02/counter/decrement_button.hpp] -[mitchell02_decrement_button_header] +[mitchell02_decrement_button] [import ../example/mitchell02/counter/counter.hpp] -[mitchell02_counter_header] +[mitchell02_counter] [import ../example/mitchell02/counter_main.cpp] [mitchell02_counter_main] -[endsect] -[section \[Stroustrup97\] String: Throw when contract is broken] -[import ../example/stroustrup97/string.hpp] -[stroustrup97_string_header] +[heading \[Stroustrup97\] String: Throw when contracts fail] [import ../example/stroustrup97/string.cpp] [stroustrup97_string] -[import ../example/stroustrup97/string_main.cpp] -[stroustrup97_string_main] -[endsect] -[section \[Cline90\] Vector: Comparison with A++ proposed syntax] +[heading \[Cline90\] Vector: Comparison with A++ proposed syntax] [import ../example/cline90/vector.hpp] [import ../example/cline90/vector_main.cpp] -[import ../example/cline90/vector_app.hpp] +[import ../example/cline90/vector_axx.hpp] [table - [ [This Library (C++03)] [A++ Proposal (not part of C++)] ] - [ [[cline90_vector_header]] [[cline90_vector_app_header]] ] + [ [This Library] [A++ Proposal (not part of C++)] ] + [ [[cline90_vector]] [[cline90_vector_axx]] ] [ [[cline90_vector_main]] [] ] ] -[endsect] -[section \[Cline90\] Stack: Function-Try blocks and exception specifications] +[heading \[Cline90\] Stack: Stack-like container] [import ../example/cline90/stack.cpp] [cline90_stack] -[endsect] -[section \[Cline90\] Vector-Stack: Subcontracting from Abstract Data Type (ADT)] +[heading \[Cline90\] Vector-Stack: Subcontracting] [import ../example/cline90/vstack.cpp] [cline90_vstack] -[endsect] -[section \[Cline90\] Calendar: A very simple calendar] +[heading \[Cline90\] Calendar: A very simple calendar] [import ../example/cline90/calendar.cpp] [cline90_calendar] -[endsect] [endsect] diff --git a/doc/qbk/grammar.qbk b/doc/qbk/grammar.qbk deleted file mode 100644 index c9d56bb..0000000 --- a/doc/qbk/grammar.qbk +++ /dev/null @@ -1,888 +0,0 @@ - -[/ Copyright (C) 2008-2012 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) ] -[/ Home at http://sourceforge.net/projects/contractpp ] - -[def __assertion__ [link assertion_anchor [^['assertion]]]] -[def __assertion_condition__ [link assertion_condition_anchor [^['assertion-condition]]]] -[def __assertion_expression__ [link assertion_expression_anchor [^['assertion-expression]]]] -[def __assertions__ [link assertions_anchor [^['assertions]]]] -[def __base_classes__ [link base_classes_anchor [^['base-classes]]]] -[def __boolean_condition__ [link boolean_condition_anchor [^['boolean-condition]]]] -[def __class_declaration__ [link class_declaration_anchor [^['class-declaration]]]] -[def __class_invariant__ [link class_invariant_anchor [^['class-invariant]]]] -[def __class_invariants__ [link class_invariants_anchor [^['class-invariants]]]] -[def __concepts__ [link concepts_anchor [^['concepts]]]] -[def __exception_specifications__ [link exception_specifications_anchor [^['exception-specifications]]]] -[def __function_declaration__ [link function_declaration_anchor [^['function-declaration]]]] -[def __function_name__ [link function_name_anchor [^['function-name]]]] -[def __function_parameters__ [link function_parameters_anchor [^['function-parameters]]]] -[def __fundamental_type__ [link fundamental_type_anchor [^['fundamental-type]]]] -[def __inscope_variables__ [link inscope_variables_anchor [^['inscope-variables]]]] -[def __loop_variant__ [link loop_variant_anchor [^['loop-variant]]]] -[def __member_initializers__ [link member_initializers_anchor [^['member-initializers]]]] -[def __named_function_parameter__ [link named_function_parameter_anchor [^['named-function-parameter]]]] -[def __named_function_parameters__ [link named_function_parameters_anchor [^['named-function-parameters]]]] -[def __named_parameter_declaration__ [link named_parameter_declaration_anchor [^['named-parameter-declaration]]]] -[def __named_template_parameter__ [link named_template_parameter_anchor [^['named-template-parameter]]]] -[def __named_template_parameters__ [link named_template_parameters_anchor [^['named-template-parameters]]]] -[def __named_template_template_parameter__ [link named_template_template_parameter_anchor [^['named-template-template-parameter]]]] -[def __named_type_template_parameter__ [link named_type_template_parameter_anchor [^['named-type-template-parameter]]]] -[def __named_value_template_parameter__ [link named_value_template_parameter_anchor [^['named-value-template-parameter]]]] -[def __oldof_declaration__ [link oldof_declaration_anchor [^['oldof-declaration]]]] -[def __operator_name__ [link operator_name_anchor [^['operator-name]]]] -[def __positional_function_parameter__ [link positional_function_parameter_anchor [^['positional-function-parameter]]]] -[def __positional_function_parameters__ [link positional_function_parameters_anchor [^['positional-function-parameters]]]] -[def __positional_template_parameter__ [link positional_template_parameter_anchor [^['positional-template-parameter]]]] -[def __positional_template_parameters__ [link positional_template_parameters_anchor [^['positional-template-parameters]]]] -[def __positional_template_template_parameter__ [link positional_template_template_parameter_anchor [^['positional-template-template-parameter]]]] -[def __positional_type_template_parameter__ [link positional_type_template_parameter_anchor [^['positional-type-template-parameter]]]] -[def __positional_value_template_parameter__ [link positional_value_template_parameter_anchor [^['positional-value-template-parameter]]]] -[def __result_oldof_assertions__ [link result_oldof_assertions_anchor [^['result-oldof-assertions]]]] -[def __result_type__ [link result_type_anchor [^['result-type]]]] -[def __select_assertion__ [link select_assertion_anchor [^['select-assertion]]]] -[def __template_parameters__ [link template_parameters_anchor [^['template-parameters]]]] -[def __template_specializations__ [link template_specializations_anchor [^['template-specializations]]]] -[def __type_keyword__ [link type_keyword_anchor [^['type-keyword]]]] -[def __type_qualifier__ [link type_qualifier_anchor [^['type-qualifier]]]] -[def __wrapped_type__ [link wrapped_type_anchor [^['wrapped-type]]]] - -[def __boolean_expression__ [link boolean_expression_anchor [^[*boolean-expression]]]] -[def __boolean_expression_using_inscope_variables__ [link boolean_expression_using_inscope_variables_anchor [^[*boolean-expression-using-inscope-variables]]]] -[def __boost_concept__ [link boost_concept_anchor [^[*boost-concept]]]] -[def __catch_declaration__ [link catch_declaration_anchor [^[*catch-declaration]]]] -[def __catch_instructions__ [link catch_instructions_anchor [^[*catch-instructions]]]] -[def __class_name__ [link class_name_anchor [^[*class-name]]]] -[def __class_type__ [link class_type_anchor [^[*class-type]]]] -[def __constant_boolean_expression__ [link constant_boolean_expression_anchor [^[*constant-boolean-expression]]]] -[def __constant_string_literal__ [link constant_string_literal_anchor [^[*constant-string-literal]]]] -[def __exception_type__ [link exception_type_anchor [^[*exception-type]]]] -[def __function_identifier__ [link function_identifier_anchor [^[*function-identifier]]]] -[def __inscope_variable__ [link inscope_variable_anchor [^[*inscope-variable]]]] -[def __loop_declaration__ [link loop_declaration_anchor [^[*loop-declaration]]]] -[def __member_initializer__ [link member_initializer_anchor [^[*member-initializer]]]] -[def __named_argument_identifier_name__ [link named_argument_identifier_anchor [^[*named-argument-identifier]]]] -[def __named_parameter_identifier_namespace__ [link named_parameter_identifier_namespace_anchor [^[*named-parameter-identifier-namespace]]]] -[def __namespace_alias__ [link namespace_alias_anchor [^[*namespace-alias]]]] -[def __natural_expression__ [link natural_expression_anchor [^[*natural-expression]]]] -[def __natural_expression_using_inscope_variables__ [link natural_expression_using_inscope_variables_anchor [^[*natural-expression-using-inscope-variables]]]] -[def __new_type_name__ [link new_type_name_anchor [^[*new-type-name]]]] -[def __oldof_expression__ [link oldof_expression_anchor [^[*oldof-expression]]]] -[def __operator_identifier__ [link operator_identifier_anchor [^[*operator-identifier]]]] -[def __operator_symbol__ [link operator_symbol_anchor [^[*operator-symbol]]]] -[def __parameter_default__ [link parameter_default_anchor [^[*parameter-default]]]] -[def __parameter_name__ [link parameter_name_anchor [^[*parameter-name]]]] -[def __template_parameter__ [link template_parameter_anchor [^[*template-parameter]]]] -[def __template_specialization__ [link template_specialization_anchor [^[*template-specialization]]]] -[def __type__ [link type_anchor [^[*type]]]] -[def __typedef_type__ [link typedef_type_anchor [^[*typedef-type]]]] -[def __unary_boolean_metafunction__ [link unary_boolean_metafunction_anchor [^[*unary-boolean-metafunction]]]] -[def __using_directive__ [link using_directive_anchor [^[*using-directive]]]] -[def __variable_name__ [link variable_name_anchor [^[*variable-name]]]] - -[section Grammar] - -[:['["Almost every macro demonstrates a flaw in the programming language, in the program, or in the programmer.]]] -[:['-- Bjarne Stroustrup (see __Stroustrup97__ page 160)]] - -This library uses macros to overcome a limitation of C++, namely the fact that the core language does not support preconditions, postconditions, class invariants, old values, and subcontracting. -This section lists the complete grammar of the syntax used by this library macros. - -[#syntax_error_warning_anchor] -[warning -In general, an error in programming this library syntax will generate cryptic compiler errors (often exposing internal code from this library and from __Boost_Preprocessor__). -[footnote -Usually, the complexity of C++ definitions is greater than the complexity of C++ declaration and the fact that this library macros only affect declarations would help by preserving the usefulness of the compiler error messages for the definition code. -However, this library aims to make declarations more complex by adding program specifications to them (preconditions, postconditions, etc). -Therefore, it can no longer be argued that declarations are significantly simpler than definitions and it would be rather helpful to have sensible compiler error messages at least for the declarations with contracts. -] - -There are intrinsic limitations on the amount of error checking that can be implemented by this library because it uses the preprocessor to parse its syntax (e.g., there is no way the preprocessor can gracefully detect and report unbalanced round parenthesis `( ... /* missing closing parenthesis here */` or an invalid concatenation symbol `BOOST_PP_CAT(xyz, ::std::vector)`). -In addition, for a given macro all compiler error messages report the same line number (because macros always expand on a single line) so line numbers are not very useful in identifying syntactic errors. - -While the preprocessor imposes limits on the error checking that can be implemented, the current version of this library does not focus on providing the best possible syntax error messages (this will be the focus of future releases, see also [@https://sourceforge.net/apps/trac/contractpp/ticket/44 Ticket 44]). -] - -The best way to resolve syntactic errors is for programmers to inspect the code ["by eye] instead of trying to make sense of the compiler errors. -This section is very useful for programmers to make sure that they are using the syntax correctly. - -[section Preprocessor DSEL] - -The syntax used by this library macros effectively defies a new language within C++. -More precisely, this library macros define a [@http://en.wikipedia.org/wiki/Domain-specific_language Domain-Specific Embedded Language (DSEL)] that replaces the usual C++ syntax for class and function declarations. -This is the ['Language of Contract++] (or ['LC++] for short). - -In contrast with other DSEL hosted by C++ which are parsed using template meta-programming (e.g., __Boost_Phoenix__), this library DSEL is parsed ["one meta-programming level higher] using preprocessor meta-programming. -Using both processor meta-programming and template meta-programming allows this library to implement rules like this: - - ``/if a member function is not public then it does not check the class invariants/`` - -This rule cannot be implemented using only template meta-programming because it is not possible to check if a function is public using template meta-programming introspection techniques. -For example, it is not possible to implement a boolean meta-function like the following: -[footnote -Using __CXX11__, it /might/ be possible to implement the `is_public` template because __SFINAE__ was extended to support access level (but to the authors' knowledge such a meta-function has not been implemented yet so the authors cannot be sure that `is_public` can be properly implemented even using __CXX11__ __SFINAE__). -Even if that were possible in __CXX11__, this library still needs declaration traits other than `public` in oder to properly implement Contract Programming (e.g., if a function is `virtual` or not in order to implement subcontracting, and there are examples like that). -Therefore, the arguments made here for the need to use a preprocessor DSEL in oder to properly implement Contract Programming in C++ hold even if `is_public` could be implemented in __CXX11__. -] - - template< ... > - struct is_public { ... }; // Unfortunately, this cannot be implemented. - -Instead a macro can be programmed to parse the following function declarations and expand to `1` if and only if the function is public: - - #define IS_PUBLIC(function_declaration) ... // This can be implemented. - - IS_PUBLIC( public void (f) ( int x ) ) // Expand to 1. - IS_PUBLIC( private void (g) ( int y ) ) // Expand to 0. - IS_PUBLIC( void (h) ( int z ) ) // Expand to 0. - -There are more examples of class and function declaration traits (`virtual`, etc) that need to be known to correctly implement Contract Programming but that cannot be inspected using template meta-programming. -This library macros can instead parse the specified class and function declarations extracting /any/ declaration trait (if a constructor is `explicit`, if a member function is `virtual`, if a base class is `protected`, if a parameter has a default value, etc). - -It should be noted that while the syntax of the DSEL defined by this library macros is rather extensive and complex, macros always define a DSEL that is intrinsically different from the core C++ language. -For example, consider the following function-like macro: - - #define F(x, y) (int(x) - int(y)) - - template< typename X, typename Y > - int f ( X const& x, Y const& y ) { return (int(x) - int(y)); } - - int main ( void ) - { - std::cout << F( , 2) << std::endl; // OK, no syntax error, it prints `-2`. - std::cout << f( , 2) << std::endl; // Compiler generates a syntax error. - return 0; - } - -Note how it is valid to invoke the macro with an empty parameter `F( , 2)` while it is syntactically invalid to invoke a function with an empty parameter `f( , 2)`. -This very simple macro already shows fundamental differences between the syntax of macros and the syntax of the core language. - -[endsect] - -[section Differences with C++ Syntax] - -The following is a summary of all the differences between the syntax of this library macros and the usual C++ class and function declaration syntax. - -[table -[ [Rule] [Syntactic Element] [Syntax Differences] ] -[ [1] [Template Declarations] [ -Use round parenthesis `template( `[^['template-parameters]]` )` instead of angular parenthesis `template< `[^['template-parameters]]` >` to declare templates (note that template instantiations are not template declarations and they use angular parenthesis as usual). -] ] -[ [2] [Template Specializations] [ -Use round parenthesis `( `[^['template-specializations]]` )` instead of angular parenthesis `< `[^['template-specializations]]` >` after a class template name to specify template specialization arguments. -] ] -[ [3] [Class, Function, and Operator Names] [ -Wrap class and function declaration names within round parenthesis `(`[^['class-name]]`)` and `(`[^['function-name]]`)`. -Use `operator(`[^['symbol]]`)(`[^['arbitrary-name]]`)` for operators (allowed but not required for `operator new`, `operator delete`, and implicit type conversion operators for fundamental types with no symbol). -Always use `operator comma` for comma operator. -Memory member operators must always be explicitly declared `static`. -] ] -[ [4] [Base Classes] [ -Use `extends( `[^['base-classes]]` )` instead of the column symbol `: `[^['base-classes]] to inherit from base classes. -] ] -[ [5] [Default Parameters] [ -Use `default `[^['parameter-default]] instead of the assignment symbol `= `[^['parameter-default]] to specify template and function parameter default values. -] ] -[ [6] [Member Access Levels] [ -Always specify the access level `public`, `protected`, or `private` (note no trailing comma `:`) for every constructor, destructor, member function, and nested class declaration. -] ] -[ [7] [Result and Parameter Types] [ -Wrap function result and parameter types within round parenthesis `(`[^['type]]`)`. -The wrapping parenthesis are allowed but not required for fundamental types containing only alphanumeric tokens (e.g., both `(const unsigned int)` and `const unsigned int` are allowed, only `(int&)` and not `int&` is allowed because of the non-alphanumeric symbol `&`, only `(mytype)` is allowed because `mytype` is not a fundamental type). -] ] -[ [8] [Member Initializers] [ -Use `initialize( `[^['member-initializers]]` )` instead of the column symbol `: `[^['member-initializers]] to specify constructor member initializers. -] ] -[ [9] [Empty Lists] [ -Specify empty lists (parameters, exception specifications, template specializations, etc) using `( void )` instead of `( )` or `< >`. -] ] -[ [10] [Commas and Leading Symbols] [ -Syntactic elements containing commas and leading non-alphanumeric symbols must be wrapped within extra round parenthesis `(...)`. -(Note that `'a'`, `"abc"`, `1.23`, etc are not alphanumeric so they need to be wrapped as `('a')`, `("abc")`, `(1.23)`, etc when specified as default parameters or similar.) -] ] -] - -[important -In general, every token which is not a known keyword (`int` is a known keyword but the function name is not) or that contains a non-alphanumeric symbol (e.g., `int&`) must be wrapped within round parenthesis `(...)` unless it is the very last token of a syntactic element (e.g., the function parameter name). -] - -Sometimes the C++ syntax allows to equivalently specify elements in different orders (e.g., `const volatile` and `volatile const` are both allowed for member functions and they have the same meaning). -The syntax of this library requires instead to specify the elements exactly in the order listed by this grammar (e.g., only `const volatile` is allowed for member functions). -[footnote -*Rationale.* -This library macros could be implemented to allow to specify syntactic elements in different orders but that would complicate the macro implementation and this grammar with no additional feature for the user. -] - -[endsect] - -[section Macro Interface] - -This library uses the following macros. - - ``[macroref CONTRACT_CLASS]``(__class_declaration__) - ``[macroref CONTRACT_CLASS_TPL]``(__class_declaration__) - - ``[macroref CONTRACT_CLASS_INVARIANT]``(__class_invariants__) - ``[macroref CONTRACT_CLASS_INVARIANT_TPL]``(__class_invariants__) - - ``[macroref CONTRACT_FUNCTION]``(__function_declaration__) - ``[macroref CONTRACT_FUNCTION_TPL]``(__function_declaration__) - ``[macroref CONTRACT_CONSTRUCTOR]``(__function_declaration__) - ``[macroref CONTRACT_CONSTRUCTOR_TPL]``(__function_declaration__) - ``[macroref CONTRACT_DESTRUCTOR]``(__function_declaration__) - ``[macroref CONTRACT_DESTRUCTOR_TPL]``(__function_declaration__) - - ``[macroref CONTRACT_FREE_BODY]``(__function_name__) - ``[macroref CONTRACT_MEMBER_BODY]``(__function_name__) - ``[macroref CONTRACT_CONSTRUCTOR_BODY]``(__class_type__, __class_name__) - ``[macroref CONTRACT_DESTRUCTOR_BODY]``(__class_type__, ~__class_name__) - - ``[macroref CONTRACT_BLOCK_INVARIANT]``(__assertions__) - ``[macroref CONTRACT_BLOCK_INVARIANT_TPL]``(__assertions__) - - ``[macroref CONTRACT_LOOP]``(__loop_declaration__) - ``[macroref CONTRACT_LOOP_VARIANT]``(__loop_variant__) - ``[macroref CONTRACT_LOOP_VARIANT_TPL]``(__loop_variant__) - - ``[macroref CONTRACT_CONSTRUCTOR_ARG]``(__parameter_name__) - ``[macroref CONTRACT_PARAMETER_TYPEOF]``(__parameter_name__) - ``[macroref CONTRACT_PARAMETER]``(__named_parameter_declaration__) - ``[macroref CONTRACT_TEMPLATE_PARAMETER]``(__named_parameter_declaration__) - ``[macroref CONTRACT_PARAMETER_BODY]``(__function_name__) - -The macros with the trailing `_TPL` must be used when the enclosing scope is type-dependent (e.g., within templates). - -[endsect] - -[section Lexical Conventions] - -The following conventions are used to express this grammar. - -[table -[ [Lexical Expression] [Meaning] ] -[ [[^['[]tokens['\]]]] [ -Either `tokens` or nothing (optional tokens). -] ] -[ [[^['{]expression['}]]] [ -The result of the enclosed expression `expression` (evaluation order). -] ] -[ [[^tokens1 ['|] tokens2]] [ -Either `tokens1` or `tokens2` (["or] operation). -] ] -[ [[^tokens['*]]] [ -`tokens` repeated zero or more times (repetition starting from zero). -] ] -[ [[^tokens['+]]] [ -`tokens` repeated one or more times (repetition starting from one). -] ] -[ [[^token, ...]] [ -A comma separated list of tokens that could also have one single element (i.e., `token` or `token1, token2` or `token1, token2, token3`). -See the __No_Variadic_Macros__ section for compilers that do not support variadic macros. -] ] -[ [[^[*tokens]]] [ -Terminal symbols (in bold font). -] ] -[ [[^['tokens]]] [ -Non-terminal symbols (in italic font). -] ] -] - -[endsect] - -[section Class Declarations] - - __class_declaration__``: [#class_declaration_anchor]`` - ``/[/````/[/``export``/]/`` template( __template_parameters__ ) ``/[/``requires( __concepts__ )``/]/````/]/`` - ``/[/``friend``/]/`` ``/{/``class ``/|/`` struct``/}/`` (__class_name__)``/[/``( __template_specializations__ )``/]/`` ``/[/``final``/]/`` - ``/[/``extends( __base_classes__ )``/]/`` - -[endsect] - -[section Base Classes] - - __base_classes__``: [#base_classes_anchor]`` - ``/[/``public ``/|/`` protected ``/|/`` private``/]/`` ``/[/``virtual``/]/`` __class_type__, ... - -Note that when specified, `virtual` must appear after the inheritance access level for a base class. - -[endsect] - -[section Template Specializations] - - __template_specializations__``: [#template_specializations_anchor]`` - __template_specialization__, ... - -[endsect] - -[section Template Parameters] - - __template_parameters__``: [#template_parameters_anchor]`` - void ``/|/`` - __positional_template_parameters__ ``/|/`` - __named_template_parameters__ - - __positional_template_parameters__``: [#positional_template_parameters_anchor]`` - __positional_template_parameter__, ... - __positional_template_parameter__``: [#positional_template_parameter_anchor]`` - __positional_type_template_parameter__ ``/|/`` - __positional_value_template_parameter__ ``/|/`` - __positional_template_template_parameter__ - __positional_type_template_parameter__``: [#positional_type_template_parameter_anchor]`` - ``/{/``class ``/|/`` typename``/}/`` __parameter_name__ - ``/[/``, default __parameter_default__``/]/`` - __positional_value_template_parameter__``: [#positional_value_template_parameter_anchor]`` - __wrapped_type__ __parameter_name__ - ``/[/``, default __parameter_default__``/]/`` - __positional_template_template_parameter__``: [#positional_template_template_parameter_anchor]`` - template( __template_parameter__, ... ) class __parameter_name__ - ``/[/``, default __parameter_default__``/]/`` - - __named_template_parameters__``: [#named_template_parameters_anchor]`` - ``/[/``using namespace __named_parameter_identifier_namespace__,``/]/`` - __named_type_template_parameter__, ... - __named_type_template_parameter__``: [#named_type_template_parameter_anchor]`` - ``/[/``deduce``/]/`` in ``/{/``class ``/|/`` typename``/}/`` - ``/[/``requires(__unary_boolean_metafunction__)``/]/`` __parameter_name__ - ``/[/``, default __parameter_default__``/]/`` - -Note that if `typename` appears within __wrapped_type__ for a value template parameter then it will be wrapped within parenthesis `(typename ...)` so it is syntactically distinguishable from the `typename` leading a type template parameter. - -Unfortunately, named template parameters only support type template parameters. -Named value template parameters and named template template parameters are not supported because they are not supported by __Boost_Parameter__ but if they were ever supported, they could follow this syntax: - - __named_template_parameters__``:`` - __named_template_parameter__, ... - __named_template_parameter__``: [#named_template_parameter_anchor]`` - __named_type_template_parameter__ ``/|/`` - __named_value_template_parameter__ ``/|/`` - __named_template_template_parameter__ - __named_value_template_parameter__``: [#named_value_template_parameter_anchor]``// Not supported. - ``/[/``deduce``/]/`` in - ``/{/``__wrapped_type__ ``/|/`` auto ``/|/`` requires(__unary_boolean_metafunction__)``/}/`` __parameter_name__ - ``/[/``, default __parameter_default__``/]/`` - __named_template_template_parameter__``: [#named_template_template_parameter_anchor]``// Not supported. - ``/[/``deduce``/]/`` in template( __positional_template_parameter__, ... ) class - ``/[/``requires(__unary_boolean_metafunction__)``/]/`` __parameter_name__ - ``/[/``, default __parameter_default__``/]/`` - - template( // For example... - // Named type template parameter (supported). - in typename requires(is_const<_>) T, default int - // Named value template parameter (not supported). - , in requires(is_converible<_, T>) val, default 0 - // Named template template parameter (not supported). - , in template( - typename A - , template( - typename X - , typename Y, default int - ) class B, default b - ) class requires(pred1< _ >) Tpl, default tpl - ) - -[endsect] - -[section Concepts] - - __concepts__``: [#concepts_anchor]`` - __boost_concept__, ... - -[endsect] - -[section Types] - - __wrapped_type__``: [#wrapped_type_anchor]`` - __fundamental_type__ ``/|/`` (__fundamental_type__) ``/|/`` (__type__) - - __fundamental_type__``: [#fundamental_type_anchor]`` - __type_qualifier__``/*/`` __type_keyword__ __type_qualifier__``/*/`` - __type_qualifier__``: [#type_qualifier_anchor]`` - const ``/|/`` volatile ``/|/`` long ``/|/`` short ``/|/`` signed ``/|/`` unsigned - __type_keyword__``: [#type_keyword_anchor]`` - void ``/|/`` bool ``/|/`` char ``/|/`` double ``/|/`` float ``/|/`` int ``/|/`` wchar_t ``/|/`` size_t ``/|/`` ptrdiff_t - -This is the syntax used to specify the function result type, the function parameter types, the types of value template parameters, etc. -As indicated by the syntax, extra parenthesis around the specified type are always allowed but they are required only for user-defined types `(mytype)` and types containing non-alphanumeric symbols `(int&)` while the parenthesis are optional for fundamental types containing no symbol `unsigned long int const` (or equivalently `(unsigned long int const)`). - -[endsect] - -[section Function Declarations] - - __function_declaration__``: [#function_declaration_anchor]`` - ``/[/``public ``/|/`` protected ``/|/`` private``/]/`` - ``/[/````/[/``export``/]/`` ``/[/``template( __template_parameters__ ) ``/[/``requires( __concepts__ )``/]/````/]/`` - ``/[/``explicit``/]/`` ``/[/``inline``/]/`` ``/[/``extern``/]/`` ``/[/``static``/]/`` ``/[/``virtual``/]/`` ``/[/``friend``/]/`` - ``/[/``__result_type__``/]/`` __function_name__ ( __function_parameters__ ) - ``/[/``requires( __concepts__ )``/]/`` - ``/[/``const``/]/`` ``/[/``volatile``/]/`` ``/[/``override ``/|/`` new``/]/`` ``/[/``final``/]/`` - ``/[/``throw( __exception_specifications__ )``/]/`` - ``/[/``precondition( __assertions__ )``/]/`` - ``/[/``postcondition( __result_oldof_assertions__ )``/]/`` - ``/[/``__member_initializers__``/]/`` - -This is the syntax used to declare all functions: Free functions, member functions, constructors, destructors, and operators. -The usual constraints of C++ function declarations apply: It is not possible to declare a static virtual member function, only constructors can use the class name as the function name, constructors and destructors have no result type, etc. -The `static` specifier can only be used for member functions (because it was deprecated for free functions from C to __CXX03__). -The `volatile` specifier must always appear after `const` when they are both specified. - -[endsect] - -[section Result Type] - - __result_type__``: [#result_type_anchor]`` - __wrapped_type__ - -Note that fundamental types containing no symbol can be specified without extra parenthesis: `void`, `bool`, `int`, `unsigned long const`, etc. - -[endsect] - -[section Function and Operator Names] - - __function_name__``: [#function_name_anchor]`` - (__function_identifier__) ``/|/`` (__class_name__) ``/|/`` (~__class_name__) ``/|/`` __operator_name__ - - __operator_name__``: [#operator_name_anchor]`` - operator(__operator_symbol__)(__operator_identifier__) ``/|/`` operator __fundamental_type__ ``/|/`` - operator new ``/|/`` operator delete ``/|/`` operator comma - -Names for free functions, member functions, constructors, and destructors are specified as usual but wrapped within parenthesis. - -Operator names are specified wrapping within parenthesis the usual operator symbol followed by an arbitrary but alphanumeric identifier: - - operator([])(at) - operator(+)(plus) - operator(())(call) - operator(new[])(new_array) - operator(delete[])(delete_array) - -Implicit type conversion operators use the same syntax: - - operator(int*)(int_ptr) - operator(mytype const&)(mytype_const_ref) - operator(std::map)(std_map) - -However, if the type is a fundamental type containing no symbol, the identifier is optional: - - operator(const int)(const_int) // Allowed but... - operator const int // ... more readable. - -Similarly, the parenthesis and identifier are optional for the `new` and `delete` operators: - - operator(new)(new_ptr) // Allowed but... - operator new // ... more readable. - - operator(delete)(delete_ptr) // Allowed but... - operator delete // ... more readable. - -Finally, the comma symbol `,` cannot be used to specify the comma operator -[footnote -*Rationale.* -Within macros a comma `,` has the special meaning of separating the macro parameters so it cannot be used to indicate the comma operator otherwise `operator(,)(mycomma)` and `operator(std::map)(stdmap)` could not be distinguished from one another by the preprocessor. -] -so the specifier `comma` must always be used to name the comma operator: - - operator comma // OK. - operator(,)(comma) // Error. - -C++ automatically promotes the memory member operators `operator new`, `operator delete`, `operator new[]`, and `operator delete[]` to be static members so the `static` specifier is allowed but optional for these member operators. -This library cannot automatically perform such a promotion so the `static` specifier is always required by this library for the memory member operators. - -[endsect] - -[section Exception Specifications] - - __exception_specifications__``: [#exception_specifications_anchor]`` - void | __exception_type__, ... - -Note that the syntax `throw( void )` is used instead of `throw( )` for no-throw specifications. - -Exception specifications apply only to exceptions thrown by the function body and not to exceptions thrown by the contracts themselves (if any) and by the contract checking code generated by this library macros. - -[endsect] - -[section Member Initializers] - - __member_initializers__``: [#member_initializers_anchor]`` - ``/[/``try``/]/`` initialize( __member_initializer__, ... ) - ``/{/``catch(__catch_declaration__) ( __catch_instructions__ )``/}*/`` - -As indicated by this syntax, it is possible to specify function-try blocks for constructor member initializers: - - struct vector_error { ... }; - - CONTRACT_CONSTRUCTOR( // Constructor with member initializers. - explicit (vector) ( int count ) - precondition( count >= 0 ) - postcondition( size() == count ) - - try initialize( ptr_(new T[count]) ) - catch(std::bad_alloc& ex) ( - std::cerr << "not enough memory for " << count << " elements vector: " << ex.what() << std::endl; - throw vector_error(1); - ) catch(std::exception& ex) ( - std::cerr << "error for " << count << " elements vector: " << ex.what() << std::endl; - throw vector_error(2); - ) catch(...) ( - std::cerr << "unknown error for " << count << " elements vector" << std::endl; - throw vector_error(3); - ) - ) { // Above function-try block only applies to exceptions thrown by the body (and not by the contracts). - ... - } - -For functions other than constructors and for constructors without member initializers, function-try blocks are programmed outside the macros and around the body definition as usual. -As specified by __N1962__, function-try blocks apply only to exceptions thrown by the function body and not to exceptions thrown by the contracts themselves (if any) and by the contract checking code generated by the library macros. - -Member initializers (and their function-try blocks) are part of the constructor definition and not of the constructor declaration. -However, __CXX03__ lack of delegating constructors requires member initializers (and their function-try blocks) to be specified within this library macros and constructors must be defined together with their declarations when they use member initializers. - -[endsect] - -[section Function Parameters] - - __function_parameters__``: [#function_parameters_anchor]`` - void ``/|/`` - __positional_function_parameters__ ``/|/`` - __named_function_parameters__ - - __positional_function_parameters__``: [#positional_function_parameters_anchor]`` - __positional_function_parameter__, ... - __positional_function_parameter__``: [#positional_function_parameter_anchor]`` - ``/[/``auto ``/|/`` register``/]/`` __wrapped_type__ __parameter_name__ - ``/[/``, default __parameter_default__``/]/`` - - __named_function_parameters__``: [#named_function_parameters_anchor]`` - ``/[/``using namespace __named_parameter_identifier_namespace__,``/]/`` - __named_function_parameter__, ... - __named_function_parameter__``: [#named_function_parameter_anchor]`` - ``/[/``deduce``/]/`` ``/{/``in ``/|/`` out ``/|/`` in out``/}/`` - ``/{/``__wrapped_type__ ``/|/`` auto ``/|/`` requires(__unary_boolean_metafunction__)``/}/`` __parameter_name__ - ``/[/``, default __parameter_default__``/]/`` - -Note that the positional parameter storage classifier `auto` is supported by this library because it is part of __CXX03__ (but the `auto` keyword changed meaning in __CXX11__ so use it with the usual care when writing code portable to __CXX11__). - -[endsect] - -[section Result and Old Values] - - __result_oldof_assertions__``: [#result_oldof_assertions_anchor]`` - ``/[/``auto __variable_name__ = return,``/]/`` - ``/[/``__oldof_declaration__, ...``/]/`` - __assertion__, ... - - __oldof_declaration__``: [#oldof_declaration_anchor]`` - ``/{/``auto ``/|/`` __wrapped_type__``/}/`` __variable_name__ = ``[macroref CONTRACT_OLDOF]`` __oldof_expression__ - -If present, result and old-of declarations should appear at the very beginning of the postconditions because they will always be visible to all assertions plus these declarations cannot be nested (within select-assertions, etc). - -The result declaration type is always `auto` because the function result type is know and already specified by the function declaration (so no result type deduction is ever needed). -The old-of declaration type is automatically deduced (using __Boost_Typeof__) when its type is specified `auto` instead of __wrapped_type__. -The macro `CONTRACT_OLDOF` does not require but allows parenthesis around the value expression __oldof_expression__ (this is as specified for the `oldof` operator in __N1962__ and similar to the `sizeof` operator which requires parenthesis when applied to a type expression `sizeof(size_type)` but not when applied to a value expression `sizeof size()`). -For example, all the followings are valid: - - auto old_size = CONTRACT_OLDOF size() - auto old_size = CONTRACT_OLDOF(size()) // Extra parenthesis around expression (optional). - (size_type) old_size = CONTRACT_OLDOF size() // Do not use Boost.Typeof. - (size_type) old_size = CONTRACT_OLDOF(size()) // No Boost.Typeof and extra parenthesis. - -If an old-of copy is performed on a type that is not __ConstantCopyConstructible__, the old-of declaration itself will not fail compilation but it will produce an old variable that will cause a compiler-error as soon as it is used in an assertion (unless the assertion specifies a requirement using a properly specialized [classref contract::has_oldof] trait). - -[endsect] - -[section Class Invariants] - - __class_invariants__``: [#class_invariants_anchor]`` - void ``/|/`` __class_invariant__, ... - - __class_invariant__``: [#class_invariant_anchor]`` - __assertion__ ``/|/`` - static class( void ``/|/`` __assertion__, ... ) ``/|/`` - volatile class( void ``/|/`` __assertion__, ... ) - -Volatile class invariants are assumed to have the same assertions as non-volatile class invariants unless they are explicitly specified. -Static class invariants are assumed to assert nothing unless they are explicitly specified. - -[endsect] - -[section Assertions] - - __assertions__``: [#assertions_anchor]`` - __assertion__, ... - __assertion__``: [#assertion_anchor]`` - using __using_directive__ ``/|/`` - namespace __namespace_alias__ ``/|/`` - typedef __typedef_type__ __new_type_name__ ``/|/`` - __assertion_condition__ - - __assertion_condition__``: [#assertion_condition_anchor]`` - __assertion_expression__ ``/|/`` - __select_assertion__ - __assertion_expression__``: [#assertion_expression_anchor]`` - __boolean_condition__ ``/|/`` - static_assert(__constant_boolean_expression__, __constant_string_literal__) - ``/[/``, requires __constant_boolean_expression__``/]/`` - __select_assertion__``: [#select_assertion_anchor]`` - if(__boolean_condition__) ( __assertion_condition__, ... ) - ``/[/``else ( __assertion_condition__, ... )``/]/`` - - __boolean_condition__``: [#boolean_condition_anchor]`` - __boolean_expression__ ``/|/`` - const( __inscope_variables__ ) __boolean_expression_using_inscope_variables__ - __inscope_variables__``: [#inscope_variables_anchor]`` - ``/[/``__wrapped_type__``/]/`` __inscope_variable__, ... - -Some basic name manipulations are allowed at the local scope where the assertions are being declared in case they are ever needed to simplify the assertion expressions. -Specifically, using-directives, namespace-aliases, and type-definitions are allowed (these will always affect all assertions within the given preconditions, postconditions, etc so it is recommended to always use these statement at the very beginning before the actual assertion conditions). -Note that these name manipulations have no effect on the program run-time state and therefore they do not compromise the contract constant-correctness requirement. - -As indicated by the grammar above, it is not possible to specify assertion requirements (using `requires`) for the entire select assertion if-then-else expression. -Eventual assertion requirements must be specified for the single assertions within the select assertion if-then-else statement and they will never disable compilation and checking of the select assertion if-condition. -Programmers can use the ternary operator `?:` instead of a select assertion if they need to specify a guarded assertion with a condition that is also disabled by the assertion requirements: - - ``/boolean-guard/`` ? __boolean_expression__ : true, requires __constant_boolean_expression__ - -Constant expressions `const( ... ) `[^['expression]] can be used to assert conditions and to check the select assertion if-condition so to fully enforce the assertion constant-correctness requirement. -However, function arguments, result value, old-of values, and the object `this` are automatically made constant by this library so constant expressions only need to be used to assert conditions on global variables, static variables, etc. -The type of the in-scope variable __inscope_variable__ is optional and it is automatically deduced using __Boost_Typeof__ when it is not specified. - -[endsect] - -[section Loop Variants] - - __loop_variant__``: [#loop_variant_anchor]`` - __natural_expression__ ``/|/`` - const( __inscope_variables__ ) __natural_expression_using_inscope_variables__ - -A loop variant must specify a non-negative integral expression that monotonically decreases at each subsequent loop iteration (the library will automatically check these two conditions at each loop iteration and terminate the loop if they are not met by calling the loop variant broken handler). -The loop variant can be specified using a constant-expression `const( ... ) `[^['expression]] so to fully enforce the contract constant-correctness requirement. - -[endsect] - -[section Named Parameter Declarations] - - __named_parameter_declaration__``: [#named_parameter_declaration_anchor]`` - ``/[/``namespace(__named_parameter_identifier_namespace__)``/]/`` - ``/[/``(__named_argument_identifier_name__)``/]/`` __parameter_name__ - -[endsect] - -[section Terminals] - -[table -[ -[Terminal] -[Description] -[If terminal contains unwrapped commas or leading symbols] -] [ -[__boolean_expression__[#boolean_expression_anchor]] -[A boolean expression: `x == 1`.] -[Wrap value within parenthesis: `(vey_sizeof::value)`.] -] [ -[__boolean_expression_using_inscope_variables__[#boolean_expression_using_inscope_variables_anchor]] -[A boolean expression that only uses in-scope variables captured as constants by a constant expression `const( ... ) `[^['expression]].] -[Wrap value within parenthesis: `(key_sizeof::value + x)`.] -] [ -[__boost_concept__[#boost_concept_anchor]] -[A concept class defined using __Boost_ConceptCheck__: `boost::CopyConstructible`.] -[Wrap type within parenthesis: `(boost::Convertible)`.] -] [ -[__catch_declaration__[#catch_declaration_anchor]] -[The declaration of an exception for a `catch` statement: `std::runtime_error& error`.] -[Wrap type using __Boost_Utility_IdentityType__: `BOOST_IDENTITY_TYPE((map::exception&)) error`.] -] [ -[__catch_instructions__[#catch_instructions_anchor]] -[The instructions of a `catch` statement terminated by semicolons `;`: `std::cout << "error" << std::endl; exit(255);`.] -[Wrap types using __Boost_Utility_IdentityType__ and values within parenthesis: `typedef BOOST_UTILITY_TYPE(std::map) mtype; (mtype m, m['a'] = 1);`.] -] [ -[__class_name__[#class_name_anchor]] -[The class name: `myclass`. For class templates this must not include the template instantiation parameters: `vector`. (For non-template classes, the class type and name are the same.)] -[Never the case.] -] [ -[__class_type__[#class_type_anchor]] -[The class type, for class templates this must include the template instantiation parameters: `vector`.] -[Wrap type within parenthesis: `(map)`.] -] [ -[__constant_boolean_expression__[#constant_boolean_expression_anchor]] -[A compile-time constant boolean expression: `sizeof(T) >= sizeof(int)`.] -[Wrap value within parenthesis: `(boost::is_convertible::value)`.] -] [ -[__constant_string_literal__[#constant_string_literal_anchor]] -[A compile-time constant string literal: `"abc"`.] -[Do nothing: `"abc"`.] -] [ -[__exception_type__[#exception_type_anchor]] -[A type: `std::exception`, `int`, `mytype`.] -[Wrap type within parenthesis: `(map::exception)`.] -] [ -[__function_identifier__[#function_identifier_anchor]] -[A valid function name identifier (C++ requires it to be alphanumeric): `f`, `push_back`, `myfunc`.] -[Never the case.] -] [ -[__inscope_variable__[#inscope_variable_anchor]] -[A variable in-scope.] -[Never the case.] -] [ -[__loop_declaration__[#loop_declaration_anchor]] -[A loop declaration: `for(int i = 0; i < 10; ++i)`, `while(i < 10)`.] -[Never the case.] -] [ -[__member_initializer__[#member_initializer_anchor]] -[A member initialization expression: `vector_(count)`.] -[Wrap object initializations within parenthesis: `(base_map())`.] -] [ -[__named_argument_identifier_name__[#named_argument_identifier_anchor]] -[The argument name to use at the calling site to pass named and deduced parameter values: `value_arg`, `NumberArg`.] -[Never the case.] -] [ -[__named_parameter_identifier_namespace__[#named_parameter_identifier_namespace_anchor]] -[The internal namespace for named and deduced parameter identifiers: `params`.] -[Never the case.] -] [ -[__namespace_alias__[#namespace_alias_anchor]] -[The argument to pass to namespace aliasing: `mpl = boost::mpl`.] -[Never the case.] -] [ -[__natural_expression__[#natural_expression_anchor]] -[A natural (i.e., non-negative integral) expression: `2 - 1`.] -[Wrap value within parenthesis: `(key_sizeof::value)`.] -] [ -[__natural_expression_using_inscope_variables__[#natural_expression_using_inscope_variables_anchor]] -[A natural (i.e., non-negative integral) expression that only uses in-scope variables captured as constant by a constant-expression: `x + 10`.] -[Wrap value within parenthesis: `(key_sizeof::value + x)`.] -] [ -[__new_type_name__[#new_type_name_anchor]] -[A new type name for `typedef` statement: `myint`.] -[Never the case.] -] [ -[__oldof_expression__[#oldof_expression_anchor]] -[A expression of type __ConstantCopyConstructible__ to pass to the [macroref CONTRACT_OLDOF] macro: `value`, `size()`.] -[Wrap value within parenthesis: `(x, y)`.] -] [ -[__operator_identifier__[#operator_identifier_anchor]] -[An arbitrary but alphanumeric identifier: `equal`, `less`, `call`.] -[Never the case.] -] [ -[__operator_symbol__[#operator_symbol_anchor]] -[The usual operator symbols: `==`, `<=`, `()`.] -[Do nothing: `std::map`.] -] [ -[__parameter_default__[#parameter_default_anchor]] -[A function or template parameter default value (either a value, a type, or a template depending on the kind of parameter): `123`.] -[Wrap value within parenthesis: `("abc")`, `('a')`, `(-123)`, `(1.23)`.] -] [ -[__parameter_name__[#parameter_name_anchor]] -[A function or template parameter name: `value`, `T`.] -[Never the case.] -] [ -[__template_parameter__[#template_parameter_anchor]] -[A usual C++ type template parameter, value template parameter, or template template parameter): `typename T`, `class U`, `int Number`, `T Value`, `template< typename X, class Y > class Template`.] -[Do nothing: `std::map Default`, `template< typename X, class Y > class Template`.] -] [ -[__template_specialization__[#template_specialization_anchor]] -[A template specialization argument (type, value, etc) that follow the class name in the declaration to specialize a template: `void (int, T)`.] -[Wrap types within parenthesis: `(std::map)`.] -] [ -[__type__[#type_anchor]] -[A type: `int`, `int const&`, `mytype`.] -[Do nothing: `std::map`.] -] [ -[__typedef_type__[#typedef_type_anchor]] -[A type: `int`, `mytype`.] -[Wrap type using __Boost_Utility_IdentityType__: `BOOST_IDENTITY_TYPE((std::map))`.] -] [ -[__unary_boolean_metafunction__[#unary_boolean_metafunction_anchor]] -[A boolean meta-function that takes one parameter: `boost::is_class`.] -[Do nothing: `boost:is_convertible`.] -] [ -[__using_directive__[#using_directive_anchor]] -[The argument to pass to a using directive: `namespace std`, `std::vector`.] -[Never the case.] -] [ -[__variable_name__[#variable_name_anchor]] -[A valid name to use to declare a variable: `result`, `old_size`.] -[Never the case.] -] -] - -If terminals contain commas not already wrapped by round parenthesis or if they start with a non-alphanumeric symbol (including tokens like `'a'`, `"abc"`, `-123`, and `1.23`), -[footnote -The C++ preprocessor cannot concatenate `1.23` because it contains the `.` symbol (even if that symbol is technically not the leading symbol). -The precise preprocessor requirement is that the concatenated symbol must be a valid macro identifier and concatenating `1.23` with any token will never give a valid macro identifier because of the presence of the dot symbol `.` (e.g., `BOOST_PP_CAT(XYZ, 1.23)` gives `XYZ1.23` which is not a valid macro identifier). -] -they need to be wrapped by extra round parenthesis `(...)` or by the __Boost_Utility_IdentityType__ `BOOST_IDENTITY_TYPE((...))` macro. -Value expressions can always be wrapped within extra around parenthesis in C++. -Type expressions can always be wrapped using __Boost_Utility_IdentityType__ but that will make the syntax less readable (and it prevents C++ from automatically deducing function template parameters) so this syntax allows to wrap type expressions within extra round parenthesis `(...)` for most terminals, including types, as indicated by the table above. - -[endsect] - -[section Alternative Assertion Syntax (Not Implemented)] - -The following alternative syntax could have been implemented to program the contract assertions: - -[table -[ [This Library Syntax] [Alternative Syntax (not implemented)] ] -[ [`` -CONTRACT_CLASS( - template( typename T ) - class (vector) -) { - ... - - CONTRACT_FUNCTION_TPL( - public (iterator) (erase) ( (iterator) where ) - precondition( - not empty(), - where != end(), - static_assert(sizeof(T) >= sizeof(int), "large enough") - ) - postcondition( - auto result = return, - auto old_size = CONTRACT_OLDOF size(), - size() == old_size - 1, - if(const( this ) this->empty()) ( - result == end() - ) - ) - ) { - return vector_.erase(where); - } -}; -`` ] [`` -CONTRACT_CLASS( - template( typename T ) - class (vector) -) { - ... - - CONTRACT_FUNCTION_TPL( - public (iterator) (erase) ( (iterator) where ) - precondition( - assert(not empty()) - assert(where != end()) - static_assert(sizeof(T) >= sizeof(int), "large enough") - ) - postcondition( - decl(auto result = return) - decl(auto old_size = CONTRACT_OLDOF size()) - assert(size() == old_size - 1) - if(const(this, this->empty())) ( - assert(result == end()) - ) - ) - ) { - return vector_.erase(where); - } -}; -``] ] -] - -An advantage of this alternative syntax is that it does not require commas at the end of each assertion. -However, when compared with this library syntax, the alternative syntax is overall more verbose, it uses more parenthesis, it deviates more from __N1962__ and __Eiffel__ (even if it is more similar to __D__), and it looks less readable at least because of `decl(...)` (in many ways this alternative syntax is equivalent to the already supported sequencing syntax from the __No_Variadic_Macros__ section with the addition of ["decoration identifiers] like `assert` which might make the code more readable but are not needed syntactically). -Therefore, the authors opted for implementing the syntax on the left hand side. - -[endsect] - -[endsect] - diff --git a/doc/qbk/introduction.qbk b/doc/qbk/introduction.qbk index 7f7398c..8acb92f 100644 --- a/doc/qbk/introduction.qbk +++ b/doc/qbk/introduction.qbk @@ -11,10 +11,10 @@ Contract Programming allows to specify preconditions, postconditions, and class These conditions assert program specifications within the source code itself allowing to find bugs more quickly during testing, making the code self-documenting, and increasing overall software quality. The following example shows how to use this library to program contracts for the [@http://www.sgi.com/tech/stl/BackInsertionSequence.html `std::vector::push_back`] member function (for simplicity, the full contracts are not programmed here, see the __Examples__ section for a fully contracted version of `std::vector`). -In order to illustrate subcontracting, this `vector` class inherits from the (somewhat arbitrary) `pushable` base class (see also [@../../example/features/push_back.cpp =push_back.cpp=]): +In order to illustrate subcontracting, this `vector` class inherits from the (somewhat arbitrary) `pushable` base class (see also [@../../example/features/introduction.cpp =introduction.cpp=]): -[import ../example/features/push_back.cpp] -[push_back] +[import ../example/features/introduction.cpp] +[introduction] This library executes the following steps when the `vector::push_back` function above is called at run-time (see also the __Contract_Programming_Overview__ section): @@ -26,13 +26,25 @@ This library executes the following steps when the `vector::push_back` function For example, if there is a bug in the function caller for which `push_back` is called when `size` is equal to `max_size` then the execution of the program will terminate with an error message similar to the following, thus it will be evident the bug is in the caller: [pre - precondition assertion "size() < max_size()" failed: file "push_back.cpp", line 33 + precondition assertion "size() < max_size()" failed: file "introduction.cpp", line 36 ] -Instead, if there is a bug in the `push_back` implementation for which `size` is not increased by `1` after `value` is added to `vector` by the function body then the execution will terminate with an error message similar to the following, thus it will be evident the bug is in the `push_back` body: +Instead, if there is a bug in the `push_back` implementation for which `size()` is not increased by `1` after `value` is added to `vector` by the function body then the execution will terminate with an error message similar to the following, thus it will be evident the bug is in the `push_back` body: [pre - postcondition assertion "size() == *old_size + 1" failed: file "push_back.cpp", line 36 + postcondition assertion "size() == *old_size + 1" failed: file "introduction.cpp", line 39 +] + +Similarly, if there is a bug in the `push_back` implementation for which `size()` is not kept greater or equal than `capacity()` then the execution will terminate with an error message similar to the following: + +[pre + exit invariant assertion "size() <= capacity()" failed: file "introduction.cpp", line 27 +] + +And, if the class invariant check failed on entering the `push_back` function call, before executing the `push_back` implementation, the message before program termination would have said: + +[pre + entry invariant assertion "size() <= capacity()" failed: file "introduction.cpp", line 27 ] By default, when an assertion fails this library prints an error message the standard error `std::cerr` and then it terminates the program calling `std::terminate` (but this behaviour can be customized to any user-defined action including throwing an exception, see the __Contract_Failure_Handlers__ section). diff --git a/doc/qbk/named_parameters.qbk b/doc/qbk/named_parameters.qbk deleted file mode 100644 index e48df60..0000000 --- a/doc/qbk/named_parameters.qbk +++ /dev/null @@ -1,426 +0,0 @@ - -[/ Copyright (C) 2008-2012 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) ] -[/ Home at http://sourceforge.net/projects/contractpp ] - -[section Named Parameters] - -This section explains how to use this library to program named parameters and deduced named parameters which are used instead of C++ usual positional parameters to specify arguments to function calls. -Parameter names are part of the program specifications and therefore named parameters are within the scope of this library. - -This library internally uses __Boost_Parameter__ to implement named parameters. -This library only offers an easier syntax for constructor and class template named parameters with respect the functionality already provided by __Boost_Parameter__, but this library allows to specify named parameters, concepts, and contracts all together within a unified syntax. - -[section Overview] - -In C++, parameters are identified with respect to their declaration position within the parameter list: The first call /argument/ (i.e., the specific value assigned to the formal parameter at the call site) maps to the first declared parameter, the second call argument maps to the second declared parameter, etc. -For example: - - window* make_window ( - char const& name, - size_t width = 10, - bool moveable = true, - bool visible = true - ) - ; - -This protocol is sufficient when there is at most one parameter with a useful default value but when there are even a few useful default parameters the positional interface becomes difficult to use at the calling site. -For example, in the following call we need to repeat the default parameter value `10`: - - bool const unmoveable = false; - make_window("warning", 10, unmoveable); // Positional (usual). - -Furthermore, it would be easier to understand the meaning of the arguments at the calling site if the parameters could be referred by their names. -For example, in order to understand if the following window is moveable and invisible, or unmoveable and visible, programmers at the calling site need to remember the order of the parameter declarations: - - make_window("note", 10, true, false); // Positional (usual). - -These issues would be solved if the parameter names could be referred at the calling site and that is what [@http://en.wikipedia.org/wiki/Named_parameter ['named parameters]] allow to do: - - make_window("warning", moveable = false); // Named. - make_widnow("note", visible = false); - -Named parameters were proposed for addition to early versions of C++ but the proposal was never accepted (see ["keyword arguments] in __Stroustrup94__). -Other programming languages support named parameters (__Ada__, __Python__, etc). - -Furthermore, /deduced named parameters/ are named parameters that can be passed in any position and without supplying their names. -These are useful when functions have parameters that can be uniquely identified (or /deduced/) based on the argument types of the function call. -For example, the `name` parameter is such a parameter, it can be deduced because no other argument, if valid, can be reasonably converted into a `char const*`. -Therefore, with a deduced parameter interface, we could pass the window name in any position without causing any ambiguity (with an appropriately designed deduced parameter interface, the caller might not even have to remember the actual parameter names): - - make_window(moveable = false, "warning"); // Deduced. - make_window("note", visible = false); - -The same reasoning applies to named template parameters and deduced named template parameters: - - template< typename ValueType, bool Shared = true > - class smart_ptr ; - - smart_ptr p1; // Positional (usual). - smart_ptr p2; // Deduced. - smart_ptr p3; // Named. - -[endsect] - -[section Named Function Parameters] - -To show how to program named parameters, we will program a named parameter interface for the [@http://www.boost.org/doc/libs/1_49_0/libs/graph/doc/depth_first_search.html Depth First Search (DFS)] algorithm of the __Boost_Graph__ library: - - template< - class Graph, - class Visitor, - class IndexMap, - class ColorMap - > requires - is_incidence_and_vertex_list_graph, - is_integral_property_map_of_key >, - is_property_map_of_key > - void depth_first_search ( - Graph const& graph, - Visitor const& visitor = dfs_visitor<>(), - vertex_descriptor const& root_vertex = - *vertices(graph).first, - IndexMap const& index_map = get(vertex_index, graph), - ColorMap& color_map = - default_color_map(num_vertices(graph), index_map) - ) - ; - -This is non-valid C++ code but it can be considered pseudo-code to illustrate the function interface that we need to program. -The concept syntax `requires` was ["borrowed] here to express parameter type requirements but a failure to satisfy such requirements is intended to fail the function call resolution and not to cause a concept error as usual. - -[variablelist -[ [=graph=] [ -This is an input parameter (`const&`), its type must match a model of both `IndicenceGraph` and `VertexListGraph`, and it has no default value (required parameter). -] ] -[ [=visitor=] [ -This is an input parameter (`const&`), its type has no requirement, and its value defaults to a DFS visitor (optional parameter). -] ] -[ [=root_vertex=] [ -This is an input parameter (`const&`), its type must be `vertex_descriptor`, and its value defaults to the first vertex of the specified graph (optional parameter). -] ] -[ [=index_map=] [ -This is an input parameter (`const&`), its type must match a model of `IntegralPropertyMap` with key type `vertex_descriptor`, its value defaults to the vertex index of the specified graph (optional parameter). -] ] -[ [=color_map=] [ -This is an input and output parameter (non-constant reference `&`), its type must match a model of `PropertyMap` with key type `vertex_descriptor`, its value defaults to a map with size equal to the number of vertices of the specified graph and created from the specified `index_map` (optional parameter). -] ] -] - -[*Parameter Identifiers] - -First of all, it is necessary to declare special elements that will serve as the parameter and argument identifiers (see also [file example/named_parameters named_params_dfs.cpp]): - -[import ../example/named_parameters/named_params_dfs.cpp] -[named_params_dfs_keywords] - -For example, the first [macroref CONTRACT_PARAMETER] macro declares an identifier `graph` that is used as the parameter name in the function declaration and also an identifier `graph_` (note the trailing underscore `_`) that is used to name the argument at the call site. - -[note -By default, argument identifiers are differentiated from parameter identifiers using a trailing underscore `_` to avoid name clashes (see also the __Parameter_Identifiers__ section). -Furthermore, it is recommended to always declare these identifiers within a namespace to avoid name clashes (because different functions in different sections of the code might very well use the same parameter names so namespaces can be used to control overlapping names). -] - -For example, for a library named Graphs, all named parameter identifiers could be declared under the `graphs` namespace and maybe in a single header =graphs_params.hpp=. -Many different functions within `graphs` (for example `graphs::depth_first_search` and `graphs::breadth_first_search`) will share a number of common parameter names (for example a parameter named `graph` with parameter identifier `graphs::graph` and argument identifier `graphs::graph_`). -All these named parameters will be defined in one places in =graphs_params.hpp= and within the `graphs` namespace so programmers can conveniently control and avoid named clashes. - -[*Function Declaration] - -The function is declared using the following syntax (see also [file example/named_parameters named_params_dfs.cpp]): - -[named_params_dfs_decl] - -This example required no preconditions and no postconditions. - -[*In, In Out, and Out Parameters] - -Input parameters (i.e., constant references `const&`) are prefixed by the specifier `in` (see also the __Grammar__ section): - - in ... graph // Input parameter. - -Input and output parameters (i.e., non-constant reference `&`) are prefixed by both specifiers `in out` (in this order, see also the __Grammar__ section): - - in out ... color_map // Input-output parameter. - -Output parameters can be prefixed just by the specifier `out` but their implementation is equivalent to using the specifiers `in out` (i.e., non-constant reference `&`). -[footnote -*Rationale.* -C++ cannot express the semantics that an output parameter should be written and never read within a function because references can always be both written and read. -] -Note that a named parameter must always be specified either `in`, `in out`, or `out` (and that is what distinguish syntactically a named parameter from a positional parameter; this use of `in`, `in out`, and `out` resembles __Ada__'s syntax). -Named and positional parameters cannot be used together in the same function declaration. - -[*Parameter Types] - -Exact parameter types are specified just before the parameter name and within parenthesis (unless they are fundamental types containing no symbol, see also the __Grammar__ section): - - in (vertex_descriptor) root_vertex // Exact parameter type requirement. - -Generic parameter types (i.e., parameter types with no requirement, same as usual type template parameters) are specified using `auto` instead of the parameter type (see also the __Grammar__ section): - - in auto visitor // No parameter type requirement. - -Predicate parameter type requirements are specified using `requires(`[^['unary-boolean-metafunction]]`)` instead of the parameter type, the type of the argument specified by the function call will be required to match the specified unary boolean meta-function in order for the call to be resolved (see also the __Grammar__ section): - - in requires(is_incidence_and_vertex_list_graph) graph // Predicate parameter type requirement. - -The placeholder `boost::mpl::_` makes this expression a unary meta-function (see __Boost_MPL__) and the library will substitute such a placeholder with the argument type specified at the call site when resolving the function call. - -[*Default Parameter Values] - -Default parameter values are specified using `, default `[^['default-parameter-value]] right after the parameter declaration (see also the __Grammar__ section): - - in auto visitor, default boost::dfs_visitor<>() - -Default parameter values are not evaluated and their types are not even instantiated if an actual argument is specified by the function call. - -[note -The type and value of a parameters can be used within the declaration of other parameters. -The type of a named parameter can be accessed using the [macroref CONTRACT_PARAMETER_TYPEOF] macro (this is especially useful for generic parameter types and for parameter types with predicate requirements because these types are not known until the function call is resolved). -] - -[*Function Call] - -The `graphs::depth_first_search` function can be called using argument identifiers to name its parameters (see also [file example/named_parameters named_params_dfs.cpp]): - -[named_params_dfs_call] - -[endsect] - -[section Deduced Function Parameters] - -To show how to program deduced named parameters, we program the parameter interface for the [@http://www.boost.org/doc/libs/1_49_0/libs/python/doc/v2/def.html#def-spec `def`] function of the __Boost_Python__ library (see also [file example/named_parameters deduced_params_pydef.cpp]): - -[import ../example/named_parameters/deduced_params_pydef.cpp] -[deduced_params_pydef_decl] - -Also a precondition was specified in this example. -(Concepts for named parameters are explained later in this section.) - -Deduced parameters are named parameter that are prefixed by the `deduce` specifier (see also the __Grammar__ section): - - deduce in (char const*) docstring // Deduced input parameter. - -When calling the function `py::def` only two arguments are required `name` and `func`. -The association between any addition argument and its parameter can be deduced based on the types of the arguments specified by the function call (so the caller is neither required to remember the parameter positions nor to explicitly specify the parameter names for these arguments). - -For example, the first two calls below are equivalent and if programmers need to pass a `policy` argument that is also, for some reason, convertible to `char const*`, they can always specify the parameter name as in the third call below (see also [file example/named_parameters deduced_params_pydef.cpp]): - -[deduced_params_pydef_calls] - -[endsect] - -[section Member Function Parameters] - -The same syntax is used to specify named and deduced parameters for member functions (see also [file example/named_parameters member_named_params_callable2.cpp]): - -[import ../example/named_parameters/member_named_params_callable2.cpp] -[member_named_params_callable2] - -No contracts were specified in this example. - -[note -When the body definition of a function with named parameters is deferred from the function declaration, the body must be declared as a template function when it is defined and the special macro [macroref CONTRACT_PARAMETER_BODY] must be used to name the function. -] - -The same macro is used to name both free and member body functions because the class type is specified outside this macro. -The constructor body definition cannot be deferred from the constructor declaration (because of the lack of delegating constructors in __CXX03__). -Destructors have no named parameters (because they have no parameter). -Named parameters are not supported for operators (because of a __Boost_Parameter__ bug). -[footnote -*Rationale.* -This library syntax supports named and deduced parameters for operators. -However, __Boost_Parameter__ does not compile when used with operators because of a bug (__Boost_Parameter__ documentation claims support for operators but later revisions of __Boost_Parameter__ no longer compile when operators are used). -If __Boost_Parameter__ were to be fixed to work with operators then this library named and deduced parameters should also work with operators. -] -Therefore the [macroref CONTRACT_PARAMETER_BODY] macro is used only with free and member functions that are not operators. -[footnote -*Rationale.* -A macro [macroref CONTRACT_PARAMETER_BODY] different from [macroref CONTRACT_MEMBER_BODY] and [macroref CONTRACT_FREE_BODY] is necessary because named parameters will still be enabled even when contracts are turned off using [macroref CONTRACT_CONFIG_NO_PRECONDITIONS], etc. -] - -In this example, named parameters were specified for all `callable2::call` overloads and for the `static` member function `callable2:static_call`: - -[member_named_params_callable2_calls] - -[endsect] - -[section Constructor Parameters] - -The same syntax is used to specify named and deduced parameters for constructors (see also [file example/named_parameters constructor_named_params_family.cpp]): -[footnote -Arguably, this library offers a better syntax than __Boost_Parameter__ for constructor named and deduced parameters (because __Boost_Parameter__ requires boiler-plate code and an extra base class in order to handle constructors). -] - -[import ../example/named_parameters/constructor_named_params_family.cpp] -[constructor_named_params_family] - -Both preconditions and postconditions were specified for the constructor. - -[important -Member initializers must access named and deduced parameters using the special macro [macroref CONTRACT_CONSTRUCTOR_ARG] (otherwise the compiler will generate an error). -[footnote -*Rationale.* -This limitation comes from the lacks of delegating constructors in __CXX03__ (as with all other limitations of this library related to member initializers). -] -] - -Named and deduced parameters can be used to specify the arguments when constructing the object: - -[constructor_named_params_family_call] - -[endsect] - -[section Class Template Parameters] - -Only class templates are discussed in this section because function templates are effectively always declared when a function uses named or deduced parameters. -In fact, a function with named or deduced parameters is always a function template (possibly with fully generic templated types when the named and deduced parameters types are specified `auto`). - -To show how to program named and deduced template parameters, we will program a named parameter interface for the [@http://www.boost.org/doc/libs/1_49_0/libs/python/doc/v2/class.html#class_-spec `class_`] class template of the __Boost_Python__ library: - - template< - class ClassType, - class Bases = bases<>, - typename HeldType = not_sepcified, - typename Copyable = not_specified - > requires - is_class - class class_ ; - -[variablelist -[ [ClassType] [ -This type parameter must be a class and it has no default value (required parameter). -] ] -[ [Bases] [ -This type parameter must be a specialization of `boost::python::bases` specifying base classes if any (see `boost::python::detail::specifies_bases`) and its value defaults to `boost::python::bases<>`. -] ] -[ [HeldType] [ -This type parameter has no constraint and it is not specified by default (see `boost::python::detail::not_specified`). -] ] -[ [Copyable] [ -This type parameter must be `boost::noncopyable` if specified and it is not specified by default (see `boost::python::detail::not_specified`). -] ] -] - -[important -Unfortunately, named and deduced template parameters can only handle type template parameters (i.e., value template parameters and template template parameters are not supported). -[footnote -*Rationale.* -This library only supports named and deduced type template parameter because it internally uses __Boost_Parameter__ and __Boost_Parameter__ does not support non-type template parameters. -However, this library syntax would support named and deduced value template parameters and template template parameters if these were ever supported by __Boost_Parameter__ (see template parameters within the __Grammar__ section). -Named and deduced value template parameters can be emulated by wrapping their values into types (using `boost::mpl::int_`, `boos::mpl::bool_`, etc) at the cost of a somewhat cumbersome syntax. -] -] - -First of all, it is necessary to declare elements that will serve as template parameter and argument identifiers (see also [file example/named_parameters named_template_params_pyclass.cpp]): - -[import ../example/named_parameters/named_template_params_pyclass.cpp] -[named_template_params_pyclass_keywords] - -For example, the first [macroref CONTRACT_TEMPLATE_PARAMETER] macro declares a specifier `ClassType` that can be used as the parameter name in the class template declaration and a specifier `ClassType_` (note the trailing underscore `_`) that can be used for the template argument at the template instantiation site. - -[note -By default, template argument identifiers are differentiated from template parameter identifiers using a trailing underscore `_` to avoid name clashes (see also the __Parameter_Identifiers__ section). -Furthermore, it is recommended to always declare these identifiers within a namespace to avoid name clashes (because different class templates in different sections of the code might very well use the same template parameter names so namespaces can be used to control overlapping names). -] - -The class template is declared using a syntax similar to the one we have seen so far for named and deduced function parameters (see also [file example/named_parameters named_template_params_pyclass.cpp]): -[footnote -Arguably, this library offers a better syntax than __Boost_Parameter__ for named and deduced template parameters (because __Boost_Parameter__ requires boiler-plate code and the additional argument packing types to be programmed manually). -] - -[named_template_params_pyclass] - -Note that template parameters are always specified using `in` because they are always input parameters (they are static types). -Furthermore, `typename` or `class` must always follow the `in` specifier for type template parameters. -[footnote -*Rationale.* -This syntax was designed so it can support non-type template parameters if this library and __Boost_Parameter__ were ever extended to support value template parameters and template template parameters (see template parameters in the __Grammar__ section). -] -Predicate type requirements `requires(`[^['unary-boolean-metafunction]]`)` are optional and they are specified right after `typename` or `class` if present. -Default template parameter values are specified using `, default `[^['default-parameter-value]] as usual. -(See also the __Grammar__ section.) - -The class template `py::class_` can be instantiated using the template parameter identifiers to name the arguments (see also [file example/named_parameters named_template_params_pyclass.cpp]): -[footnote -This named and deduced parameter syntax is not entirely ideal because it uses angular parenthesis `py::ClassType_` instead of the more readable assignment operator `py::ClassType_ = bx` to name the arguments (but that is how __Boost_Parameter__ is implemented and also this library authors see no way to implement the assignment operator syntax for named and deduced template parameters). -] - -[named_template_params_pyclass_calls] - -[endsect] - -[section Concepts] - -As shown in the `py::class_` example above, it is possible to specify concepts for named and deduced template parameters. -Concepts are specified using `requires` after the class template parameter declaration: - - template( ... ) requires( ``[^['concept1]]``, ``[^['concept2]]``, ... ) - class (class_) ... - -As shown in the `py::def` example earlier in this section, it is also possible to specify concepts for named and deduced function parameters (because named and deduced function parameter can be generic, as function template parameters are, when their types are specified `auto` or via a predicate type requirement). -However, in this case concepts are specified using `requires` after the function parameter list (because there is not `template` declaration for functions with named and deduced parameters): - - void (def) ( ... ) requires( ``[^['concept1]]``, ``[^['concept2]]``, ... ) - -Note the following differences between specifying predicate type requirements and concepts for named and deduced parameters: - -* If predicate type requirements are not met, the function or class template will be taken out from the set of possible function overloads or template specializations in the function call or template instantiation resolution (this might ultimately generate a compiler error but only if there is no other function overload or template specialization that can be used). -* If a concept check fails, the compiler will always generate a compiler error. - -[endsect] - -[section Parameter Identifiers] - -When using the [macroref CONTRACT_PARAMETER] and [macroref CONTRACT_TEMPLATE_PARAMETER] macros (see also the __Grammar__ section): - -# It is possible to specify a namespace that will contain the parameter identifiers using `namespace(`[^['parameter-identifier-namespace]]`)`. -# It is also possible to specify the name of the argument identifier instead of using the automatic underscore `_` postfix using `(`[^['argument-identifier]]`)`. - -The following example generates parameter identifiers within the `params` namespace, and argument identifiers `NumberArg` and `value_arg` instead of the default `Number_` and `value_` for the `Number` and `value` parameters respectively (see also [file example/named_parameters named_param_identifiers_positive.cpp]): - -[import ../example/named_parameters/named_param_identifiers_positive.cpp] -[named_param_identifiers_positive_keywords] - -When the parameter identifier namespace is specified, it must be repeated in the named and deduced parameter declaration list (see also the __Grammar__ section): - - using namespace ``/paraemeter-identifier-namespace/``, ... // named and deduced parameters follow - -The authors find this syntax confusing so they recommend to never specify the parameter identifier namespace when using the [macroref CONTRACT_PARAMETER] and [macroref CONTRACT_TEMPLATE_PARAMETER] macros. -[footnote -*Rationale.* -The ability to specify the parameter identifier (or tag) namespace is offered because it is offered by __Boost_Parameter__ and it gives programmers greater control. -However, it should be rarely if ever needed because this library provides the [macro CONTRACT_PARAMETER_TYPEOF] macro. -] -Instead programmers are encouraged to use these macros within an enclosing namespace as done by the rest of the examples in this documentation. - -For example (see also [file example/named_parameters named_param_identifiers_positive.cpp]): - -[named_param_identifiers_positive] - -Class invariants, preconditions, and postconditions were also specified in this example. - -At the template instantiation and function call site, the specified argument identifiers `NumberArg` and `value_arg` can be used instead of the usual trailing underscore (see also [file example/named_parameters named_param_identifiers_positive.cpp]): - -[named_param_identifiers_positive_call] - -It is not necessary to specify both the parameter identifier namespace and the argument identifier as they are both and independently optional (see also the __Grammar__ section): - - CONTRACT_TEMPLATE_PARAMETER( (NumberArg) Number ) // Specify only argument identifier. - CONTRACT_PARAMETER( namespace(params) value ) // Specify only parameter identifier namespace. - -It is recommended to never specify the argument identifiers to have the same names as the parameter identifiers in order to avoid the following usually silent bug (see also [file example/named_parameters named_param_identifiers_failure.cpp]): - -[import ../example/named_parameters/named_param_identifiers_failure.cpp] -[named_param_identifiers_failure] - -The call `print(age = 3);` will assign `3` to `f`'s parameter `age` instead than passing `3` as the argument of `print`'s parameter `age`. -The trailing underscore `_` convention and enclosing the named parameter declaration macros [macroref CONTRACT_PARAMETER] and [macroref CONTRACT_TEMPLATE_PARAMETER] within a namespace make this type of name clashes unlikely. - -[endsect] - -[endsect] - diff --git a/doc/qbk/no_variadic_macros.qbk b/doc/qbk/no_variadic_macros.qbk deleted file mode 100644 index a2a50d3..0000000 --- a/doc/qbk/no_variadic_macros.qbk +++ /dev/null @@ -1,81 +0,0 @@ - -[/ Copyright (C) 2008-2012 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) ] -[/ Home at http://sourceforge.net/projects/contractpp ] - -[section No Variadic Macros] - -This section illustrates an alternative syntax, the /sequence syntax/, that can be used on compilers that do not support variadic macros. -Most modern compilers support [@http://en.wikipedia.org/wiki/Variadic_macro variadic macros] (notably, these include GCC, MSVC, and all __CXX11__ compilers). - -[warning -The sequence syntax presented in this section has not been fully tested yet. -Future revisions of the library are expected to test and support the sequence syntax more thoroughly (see also [@https://sourceforge.net/apps/trac/contractpp/ticket/58 Ticket 58]). -] - -The sequence syntax uses many extra parenthesis and it is significantly less readable than the comma-separated syntax that we have seen so far. -Therefore, it is strongly recommended to not use the sequence syntax unless it is absolutely necessary to program contracts that are portable to compilers that do not support variadic macros. - -[section Sequence Syntax] - -In the rare case that programmers need to use this library on compliers without variadic macros, this library also allows to specify its macro parameters using a __Boost_Preprocessor__ sequence in which tokens are separated using round parenthesis `()`: - - (token1) (token2) ... // All compilers. - -Instead of the comma-separated lists that we have seen so far which require variadic macros: - - token1, token2, ... // Only compilers with variadic macros (preferred). - -This library detects preprocessor support for variadic macros using the __Boost_Config__ macro `BOOST_NO_VARIADIC_MACROS`. -__Boost_Config__ defines the `BOOST_NO_VARIADIC_MACROS` only on compilers that do not support variadic macros furthermore programmers can forcefully define this macro also on compilers that support variadic macros. -When this macro is not defined, this library macros support both the camma-separated and sequence syntax, otherwise only the sequence syntax is supported. - -[note -The same macros accept both syntaxes on compilers with variadic macros and only the sequence syntax on compilers without variadic macros. -] - -For example, the syntax on the left hand side works on all compilers with and without variaidic macros (see also [file example/contracts class_template_vector_seq.cpp], [file example/contracts pushable_seq.hpp], [file example/contracts class_template_vector.cpp], and [file example/contracts pushable.hpp]): - -[import ../example/contracts/pushable_seq.hpp] -[import ../example/contracts/class_template_vector_seq.cpp] -[table -[ [Sequence Syntax (all compilers)] [Comma-Separated Syntax (variadic macros only, preferred)] ] -[ [[pushable_seq]] [[pushable]] ] -[ [[class_template_vector_seq]] [[class_template_vector]] ] -] - -Note the many extra parenthesis around all tokens within the lists: template parameters `(typename T)`, base classes `(public pushable)`, function parameters `(size_type) count`, all assertions, etc. -Furthermore, empty lists need to be specified using `(void)` instead of just `void`. - -When using the sequence syntax, the macro [macroref CONTRACT_LIMIT_OLDOFS] specifies the maximum number of postconditions sequence elements (instead of the maximum possible number of old value declarations as for variadic macros). - -[endsect] - -[section Commas and Leading Symbols in Macros] - -As we have seen in the __Advanced_Topics__ section, syntactic elements containing unwrapped commas and leading symbols need to be wrapped within extra round parenthesis: - - (::std::map >) // With variadic macros. - -However, without variadic macros this is no longer sufficient and the number of commas needs to be explicitly specified using the following syntax: -[footnote -*Rationale.* -Using variadic macros, the preprocessor can automatically determine the number of commas within a tuple but without variadic macros that is no longer possible so programmers must manually specify the number of commas. -] - - comma(2)(::std::map >) // Without variadic macros. - -For example (see also [file example/contracts macro_commas_symbols_integral_map_seq.cpp] and [file example/contracts macro_commas_symbols_integral_map.cpp]): - -[import ../example/contracts/macro_commas_symbols_integral_map_seq.cpp] -[table -[ [Sequence Syntax (all compilers)] [Comma-Separated Syntax (variadic macros only, preferred)] ] -[ [[macro_commas_symbols_integral_map_seq]] [[macro_commas_symbols_integral_map]] ] -] - -[endsect] - -[endsect] - diff --git a/doc/qbk/tutorial.qbk b/doc/qbk/tutorial.qbk index 7319140..92d34a4 100644 --- a/doc/qbk/tutorial.qbk +++ b/doc/qbk/tutorial.qbk @@ -1,25 +1,25 @@ +[import ../example/features/public.cpp] + [section Tutorial] This section gives an introduction on how to program contracts using this library. -[import ../example/features/identifiers.cpp] - [section Free Functions] Consider the following free function `inc` which increments its argument by `1` and returns the value its argument had before the increment (this function is equivalent to the usual C++ operator `int operator++(int& x, int)`). -Let's write the contract for such a function using code comments (see also [@../../example/features/inc_no_contract.cpp =inc_no_contract.cpp=]): +Let's write the contract for such a function using code comments (see also [@../../example/features/no_contracts.cpp =no_contracts.cpp=]): -[import ../../example/features/inc_no_contract.cpp] -[inc_no_contract] +[import ../../example/features/no_contracts.cpp] +[no_contracts] The precondition states that the argument to increment must be smaller than the maximum allowable value of its type (otherwise the increment will go out-of-range). The postconditions state that the argument was actually incremented by `1` and that the function return value is equal to the argument before it was incremented. -Now let's program this function and its contract using the [funcref boost::contract::function] function from this library (see also [@../../example/features/inc.cpp =inc.cpp=]): +Now let's program this function and its contract using the [funcref boost::contract::function] function from this library (see also [@../../example/features/free_function.cpp =free_function.cpp=]): -[import ../../example/features/inc.cpp] -[inc] +[import ../../example/features/free_function.cpp] +[free_function] 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 also __Getting_Started__). @@ -243,9 +243,9 @@ Therefore, it might be best for both `class`es and `struct`s to have no mutable [section Constructors] Contracts for constructors are programmed using the [funcref boost::contract::constructor] function and the [classref boost::contract::constructor_precondition] base class. -For example (see also [@../../example/features/identifiers.cpp =identifiers.cpp=]): +For example (see also [@../../example/features/public.cpp =public.cpp=]): -[unique_identifiers_constructor] +[public_constructor] It is not possible to specify preconditions using `.precondition(...)` for constructors (the library will generate a compile-time error if `.precondition(...)` is used on the object returned by [funcref boost::contract::constructor]). Constructor preconditions are specified using the [classref boost::contract:constructor_precondition] base class instead (see also __Preconditions__). @@ -294,9 +294,9 @@ They could still use [classref boost::contract::constructor_precondition] to che [section Destructors] Contracts for destructors are programmed using the [funcref boost::contract::destructor] function. -For example (see also [@../../example/features/identifiers.cpp =identifiers.cpp=]): +For example (see also [@../../example/features/public.cpp =public.cpp=]): -[unique_identifiers_destructor] +[public_destructor] It is not possible to specify preconditions for destructors (the library will generate a compile-time error if `.precondition(...)` is used here because destructors can be called at any time after construction so they have no precondition). It is possible to specify postconditions for destructors (see also __Postconditions__ and see __Static_Public_Functions__ for an example). @@ -334,9 +334,9 @@ They could use [funcref boost::contract::function] to just check postconditions Contracts for public member functions are programmed using the [funcref boost::contract::public_function] function. Let's first consider public member functions that are not static, not virtual, and do not override any function from base classes. -For example, the following such a function `find` is declared as a member of the `unique_identifiers` class (see also [@../../example/features/identifiers.cpp =identifiers.cpp=]): +For example, the following such a function `find` is declared as a member of the `unique_identifiers` class (see also [@../../example/features/public.cpp =public.cpp=]): -[unique_identifiers_find] +[public_function] It is possible to specify both preconditions and postconditions for public member functions (see also __Preconditions__ and __Postconditions__). [funcref boost::contract::public_function] takes `this` as a parameter because public member functions check class invariants (see also __Class_Invariants__). @@ -365,9 +365,9 @@ A public member function can avoid calling [funcref boost::contract::public_func [section Virtual Public Functions] Let's now consider public member functions that are virtual but that still do not override any function from base classes. -For example, the following such a function `push_back` is declared as a member of the `unique_identifiers` class (see also [@../../example/features/identifiers.cpp =identifiers.cpp=]): +For example, the following such a function `push_back` is declared as a member of the `unique_identifiers` class (see also [@../../example/features/public.cpp =public.cpp=]): -[unique_identifiers_push_back] +[public_virtual_function] Public virtual functions must declare an extra trailing parameter of type [classref boost::contract::virtual_]`*` and assign it to `0` by default (i.e., null). Because this extra parameter is the last one and it has a default value, it does not alter the calling interface of the virtual function and callers will essentially never have to deal with it explicitly (a part from when manipulating the virtual function type for function pointer type-casting, etc.). @@ -399,13 +399,13 @@ For the rest, the same considerations made in __Public_Functions__ apply. [section Overriding Public Functions (Subcontracting)] Let's now consider public member functions (virtual or not) that override public virtual functions from one or more public base class. -For example, the following such a function `push_back` is declared as a member of the `identifiers` derived class and it overrides `push_back` from the `unique_identifiers` base class (see also [@../../example/features/identifiers.cpp =identifiers.cpp=]): +For example, the following such a function `push_back` is declared as a member of the `identifiers` derived class and it overrides `push_back` from the `unique_identifiers` base class (see also [@../../example/features/public.cpp =public.cpp=]): [footnote In this document, overriding functions are often marked with the `/* override */` comment. On compilers that support C++11 virtual specifiers `override` can be used instead (`override` is not used in the documentation only because virtual specifiers are not widely supported yet, even by compilers that support other C++11 features like lambda functions). ] -[identifiers_push_back] +[public_override_function] (See the __Base_Types__ section below for more information about [macroref BOOST_CONTRACT_BASE_TYPES] and `base_types`.) @@ -413,7 +413,7 @@ Overriding public functions must always list the extra trailing parameter of typ Programmers must pass the extra virtual parameter as the very first argument to all [macroref BOOST_CONTRACT_OLDOF] and [funcref boost::contract::public_function] calls in the overriding function (as for non-overriding virtual public functions discussed above). For overriding functions, [funcref boost::contract::public_function] takes an explicit template argument `override_`[^['function-name]] that must be defined at class scope using [macroref BOOST_CONTRACT_OVERRIDE][^(['function-name])] (see right after the function). -When called from overriding public functions, [funcref boost::contract::public_function] also take a pointer to the enclosing function, the object `this` (because overriding public functions check class invariants), and references to each function argument in the order they appear in the function declaration. +When called from overriding public functions, [funcref boost::contract::public_function] also takes a pointer to the enclosing function, the object `this` (because overriding public functions check class invariants), and references to each function argument in the order they appear in the function declaration. [footnote *Rationale.* The object `this` is passed after the function pointer to follow `bind`'s syntax. @@ -449,6 +449,9 @@ This ensures that overriding public function subcontracts are checked correctly This library will generate a compile-time error if there is no suitable virtual function to overload in any of the public base classes (similar to C++11 `override` virtual specifier, but limited to functions with the extra [classref boost::contract::virtual_]`*` parameter and searched recursively only in `public` base classes passed to [macroref BOOST_CONTRACT_BASE_TYPES]). +[macroref BOOST_CONTRACT_OVERRIDE] does not have to be used in a public section of the class (see also __Access__). +[macroref BOOST_CONTRACT_OVERRIDE] must be used only once in a given class and overloaded functions can reuse it, plus [macroref BOOST_CONTRACT_NAMED_OVERRIDE] can be used to generate a name different from `override_...` (see also __Overloads_and_Named_Override__). + For the rest, the same considerations made in __Virtual_Public_Functions__ apply. [endsect] @@ -457,9 +460,9 @@ For the rest, the same considerations made in __Virtual_Public_Functions__ apply In order to support subcontracting, this library must be made aware of base classes. Programmers do that using the [macroref BOOST_CONTRACT_BASE_TYPES] macro to declared a public member type named `base_types` with a `typedef`. -For example (see also [@../../example/features/identifiers.cpp =identifiers.cpp=]): +For example (see also [@../../example/features/public.cpp =public.cpp=]): -[multi_identifiers] +[public_base_types] For convenience, a /local macro/ named `BASES` (any other name can be used) is often used here to avoid repeating the base list twice (first when inheriting `: ...` and then when calling [macroref BOOST_CONTRACT_BASE_TYPES]`(...)`). Being a local macro, `BASES` must be undefined after it has been used to declare `base_types` (to avoid macro redefinition errors). @@ -491,10 +494,10 @@ Private and protected member functions do not check class invariants (because th Instead, private and protected member functions only check preconditions and postconditions, like free functions do. Therefore, [funcref boost::contract::function] is used to program contracts for private and protected functions, like for free functions. -For example (see also [@../../example/features/countdown.cpp =countdown.cpp=]): +For example (see also [@../../example/features/private_protected.cpp =private_protected.cpp=]): -[import ../../example/features/countdown.cpp] -[countdown] +[import ../../example/features/private_protected.cpp] +[private_protected] The same considerations made in __Free_Functions__ apply. diff --git a/doc/qbk/virtual_specifiers.qbk b/doc/qbk/virtual_specifiers.qbk deleted file mode 100644 index fe3862d..0000000 --- a/doc/qbk/virtual_specifiers.qbk +++ /dev/null @@ -1,138 +0,0 @@ - -[/ Copyright (C) 2008-2012 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) ] -[/ Home at http://sourceforge.net/projects/contractpp ] - -[section Virtual Specifiers] - -This section explains how to use this library to program virtual specifiers `final`, `override`, and `new`. -Virtual specifiers are part of the program specifications because they enforce inheritance constraints at compile-time and therefore they are within the scope of this library. - -[important -This library implements virtual specifiers for __CXX03__ and without using any __CXX11__ feature. -[footnote -This library declares special member functions to ["tag] virtual traits of a given member function in a base class (if it is `virtual`, `final`, etc). -Then template meta-programming introspection is used by the derived class to inspect virtual trait in its base classes and generate compiler errors if the virtual specifiers are not satisfied. -These techniques do not use any __CXX11__ feature however, future revisions of this library might use __CXX11__ native support for virtual specifiers so to eliminate the extra compilation time required by template meta-programming introspection and correct a number of bugs associated with the current implementation of virtual specifiers in this library (see also [@http://sourceforge.net/apps/trac/contractpp/ticket/53 Ticket 53], [@http://sourceforge.net/apps/trac/contractpp/ticket/53 Ticket 55], and [@http://sourceforge.net/apps/trac/contractpp/ticket/53 Ticket 56]). -] -Obviously, virtual specifiers are supported only if both the base and derived classes and member functions in question are declared using this library macros (otherwise this library has no control over usual C++ declarations). -] - -The examples presented in this section are rather simple (and they do not define virtual destructors for brevity). -These examples only aim to illustrate the syntax of this library virtual specifiers and not to make a case about the utility of these specifiers. -Virtual specifiers were adopted by __CXX11__ and in some form are part of other languages like __Java__, programmers can refer to the web and to the __Examples__ section for more interesting examples. - -[section Final Classes] - -Final classes cannot be derived, otherwise the compiler will generated an error. -This library allows to declare a class final by specifying `final` within the [macroref CONTRACT_CLASS] macro after the class name, after template specialization types but before base classes if present (see also the __Grammar__ section). - -For example (see also [file example/virtual_specifiers final_class.hpp] and [file example/virtual_specifiers final_class.cpp]): - -[import ../example/virtual_specifiers/final_class.hpp] -[final_class] - -If a derived class declared using [macroref CONTRACT_CLASS] attempts to inherit from a final base class, the compiler will generate a compile-time error (this is true only if both the base and derived classes are declared using this library macro [macroref CONTRACT_CLASS]). -For example, consider the following derived class (see also [file example/virtual_specifiers final_class_error.cpp]): - -[import ../example/virtual_specifiers/final_class_error.cpp] -[final_class_error] - -This will generate a compile-time error similar to the following because `x` is final (note that the number of the base class that violates the `final` specifier is reported so it is clear which base class is causing the error also in case of multiple-inheritance): - -[pre -final_class_error.cpp:8 ... ERROR_cannot_extend_final_base_class_number_1 ... -] - -Final class checks are performed at compile-time even when contracts are disabled (using [macroref CONTRACT_CONFIG_NO_PRECONDITIONS], [macroref CONTRACT_CONFIG_NO_POSTCONDITIONS], [macroref CONTRACT_CONFIG_NO_CLASS_INVARIANTS], etc). - -[endsect] - -[section Final Member Functions] - -Final member functions cannot be overridden by derived classes, otherwise the compiler will generate an error. -This library allows to declare a member function final by specifying `final` within the [macroref CONTRACT_FUNCTION] macro, after the cv-qualifier but before exception specifications if present (see also the __Grammar__ section). - -For example (see also [file example/virtual_specifiers final_member.hpp] and [file example/virtual_specifiers final_member.cpp]): - -[import ../example/virtual_specifiers/final_member.hpp] -[final_member] - -If a member function of a derived class is declared using [macroref CONTRACT_FUNCTION] and attempts to override a final member function from one of the base classes, the compiler will generate a compile-time error (this is true only if both the overriding and overridden functions are declared using this library macro [macroref CONTRACT_FUNCTION]). -For example, consider the following derived class (see also [file example/virtual_specifiers final_member_error.cpp]): - -[import ../example/virtual_specifiers/final_member_error.cpp] -[final_member_error] - -This will generate a compile-time error similar to the following because `y::f` is final (note that the number of the base class that violates the `final` specifier is reported so it is clear which overridden member function is causing the error also in case of multiple-inheritance): - -[pre -final_member_error.cpp:13 ... ERROR_cannot_override_final_function_from_base_class_number_1 ... -] - -In order to correctly handle overloaded functions, the overriding function and the final function must have the same name, parameter types, and cv-qualifier to generate this error. - -Final member function checks are performed at compile-time but only when class invariants are enabled ([macroref CONTRACT_CONFIG_NO_CLASS_INVARIANTS] is left not defined). - -[endsect] - -[section Overriding Member Functions] - -Overriding member functions must override a virtual member function from one or more of the base classes, otherwise the compiler will generate an error. -This library allows to declare an overriding member function by specifying `override` within the [macroref CONTRACT_FUNCTION] macro, after the cv-qualifier but before the `final` specifier if present (`override` and `final` can be used together, see also the __Grammar__ section). - -For example (see also [file example/virtual_specifiers override_member.hpp] and [file example/virtual_specifiers override_member.cpp]): - -[import ../example/virtual_specifiers/override_member.hpp] -[override_member] - -If a member function of a derived class is declared using [macroref CONTRACT_FUNCTION] and attempts to override an non-virtual or non-existing member function from one of the base classes, the compiler will generate a compile-time error (this is true only if both the overriding and overridden functions are declared using this library macro [macroref CONTRACT_FUNCTION]). -For example, consider the following derived class (see also [file example/virtual_specifiers override_member_error.cpp]): - -[import ../example/virtual_specifiers/override_member_error.cpp] -[override_member_error] - -This will generate a compile-time error similar to the following because `x::g` is not virtual: - -[pre -override_member_error.cpp:12 ... ERROR_no_base_class_declares_matching_virtual_function_to_override_at_line_12 ... -] - -In order to correctly handle overloaded functions, the overriding function and the overridden virtual function must have the same name, parameter types, and cv-qualifier to /not/ generate this error. - -Overriding member function checks are performed at compile-time but only if at least one between preconditions, postconditions, and class invariants is enabled ([macroref CONTRACT_CONFIG_NO_PRECONDITIONS], [macroref CONTRACT_CONFIG_NO_POSTCONDITIONS] and [macroref CONTRACT_CONFIG_NO_CLASS_INVARIANTS] are not all defined at the same time). - -[endsect] - -[section New Member Functions] - -New member functions shall not override member functions from any of the base classes, otherwise the compiler will generate an error. -This library allows to declare a new member function by specifying `new` within the [macroref CONTRACT_FUNCTION] macro, after the cv-qualifier but before the `final` specifier if present (`new` and `final` can be used together, see also the __Grammar__ section). - -For example (see also [file example/virtual_specifiers new_member.hpp] and [file example/virtual_specifiers new_member.cpp]): - -[import ../example/virtual_specifiers/new_member.hpp] -[new_member] - -If a new member function of a derived class is declared using [macroref CONTRACT_FUNCTION] but it overrides an existing member function from one of the base classes, the compiler will generate a compile-time error (this is true only if both the overriding and overridden functions are declared using this library macro [macroref CONTRACT_FUNCTION]). -For example, consider the following derived class (see also [file example/virtual_specifiers new_member_error.cpp]): - -[import ../example/virtual_specifiers/new_member_error.cpp] -[new_member_error] - -This will generate a compile-time error similar to the following because `f` was already declared in `x` (note that the number of the base class that violates the `new` specifier is reported so it is clear which overridden member function is causing the error also in case of multiple-inheritance): - -[pre -new_member_error.cpp:12 ... ERROR_matching_virtual_function_already_declared_by_base_class_number_1 ... -] - -In order to correctly handle overloaded functions, the new function and the overridden function must have the same name, parameter types, and cv-qualifier to generate this error. - -New member function checks are performed at compile-time but only if at least one between preconditions, postconditions, and class invariants is enabled ([macroref CONTRACT_CONFIG_NO_PRECONDITIONS], [macroref CONTRACT_CONFIG_NO_POSTCONDITIONS] and [macroref CONTRACT_CONFIG_NO_CLASS_INVARIANTS] are not all defined at the same time). - -[endsect] - -[endsect] - diff --git a/example/cline90/calendar.cpp b/example/cline90/calendar.cpp index 8dd3336..9380b6c 100644 --- a/example/cline90/calendar.cpp +++ b/example/cline90/calendar.cpp @@ -1,4 +1,5 @@ +//[cline90_calendar #include #include @@ -78,4 +79,5 @@ int main() { return boost::report_errors(); } +//] diff --git a/example/cline90/stack.cpp b/example/cline90/stack.cpp index 7bef246..69de81c 100644 --- a/example/cline90/stack.cpp +++ b/example/cline90/stack.cpp @@ -1,4 +1,5 @@ +//[cline90_stack #include #include #include @@ -85,4 +86,5 @@ int main() { BOOST_TEST_EQ(s.pop(), 123); return boost::report_errors(); } +//] diff --git a/example/cline90/vector.hpp b/example/cline90/vector.hpp index bb18ef2..409d21d 100644 --- a/example/cline90/vector.hpp +++ b/example/cline90/vector.hpp @@ -1,4 +1,5 @@ +//[cline90_vector #ifndef VECTOR_HPP_ #define VECTOR_HPP_ @@ -93,4 +94,5 @@ private: }; #endif // #include guard +//] diff --git a/example/cline90/vector_axx.hpp b/example/cline90/vector_axx.hpp index 2a0207d..ef218b9 100644 --- a/example/cline90/vector_axx.hpp +++ b/example/cline90/vector_axx.hpp @@ -1,13 +1,6 @@ -// Copyright (C) 2008-2012 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) -// Home at http://sourceforge.net/projects/contractpp - -//[cline90_vector_app_header -// File: vector_app.hpp -// Extra spaces, newlines, etc used to align text with this library code. +//[cline90_vector_axx +// Extra newlines, etc used to align text with this library code. diff --git a/example/cline90/vector_main.cpp b/example/cline90/vector_main.cpp index f3d8c70..514761f 100644 --- a/example/cline90/vector_main.cpp +++ b/example/cline90/vector_main.cpp @@ -1,4 +1,5 @@ +//[cline90_vector_main #include "vector.hpp" #include @@ -13,4 +14,5 @@ int main() { return boost::report_errors(); } +//] diff --git a/example/cline90/vstack.cpp b/example/cline90/vstack.cpp index 512e1c0..ad10af7 100644 --- a/example/cline90/vstack.cpp +++ b/example/cline90/vstack.cpp @@ -1,4 +1,5 @@ +//[cline90_vstack #include "vector.hpp" #include #include @@ -223,4 +224,5 @@ int main() { return boost::report_errors(); } +//] diff --git a/example/features/access.cpp b/example/features/access.cpp new file mode 100644 index 0000000..484a011 --- /dev/null +++ b/example/features/access.cpp @@ -0,0 +1,81 @@ + +#include +#include +#include + +template +class pushable { +public: + void invariant() const { + BOOST_CONTRACT_ASSERT(capacity() <= max_size()); + } + + virtual void push_back(T const& value, boost::contract::virtual_* v = 0) + = 0; + + virtual std::size_t max_size() const = 0; + virtual std::size_t capacity() const = 0; +}; + +template // Contract for pure virtual function. +void pushable::push_back(T const& value, boost::contract::virtual_* v) { + auto old_capacity = BOOST_CONTRACT_OLDOF(v, capacity()); + auto c = boost::contract::public_function(v, this) + .precondition([&] { + BOOST_CONTRACT_ASSERT(capacity() < max_size()); + }) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(capacity() >= *old_capacity); + }) + ; +} + + +//[access +template +class vector + #define BASES public pushable + : BASES +{ + // In private section: + friend class boost::contract::access; // Friend `access` class so... + + typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types; // ...private bases. + #undef BASES + + void invariant() const { // ...private invariants (static and non). + BOOST_CONTRACT_ASSERT(size() <= capacity()); + } + +public: + virtual void push_back(T const& value, boost::contract::virtual_* v = 0) + /* override */ { + auto old_size = BOOST_CONTRACT_OLDOF(v, size()); + auto c = boost::contract::public_function( + v, &vector::push_back, this, value) + .precondition([&] { + BOOST_CONTRACT_ASSERT(size() < max_size()); + }) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(size() == *old_size + 1); + }) + ; + + vect_.push_back(value); + } + +private: + BOOST_CONTRACT_OVERRIDE(push_back) // Allowed even without friend `access`. + std::vector vect_; + + /* ... */ +//] + +public: + // TODO: Write contracts for those too. + std::size_t size() const { return vect_.size(); } + std::size_t max_size() const { return vect_.max_size(); } + std::size_t capacity() const { return vect_.capacity(); } +}; +//] + diff --git a/example/features/call_if.cpp b/example/features/call_if.cpp new file mode 100644 index 0000000..61b5121 --- /dev/null +++ b/example/features/call_if.cpp @@ -0,0 +1,38 @@ + +//[call_if +template +class vector { +public: + void push_back(T const& value) { + auto old_size = BOOST_CONTRACT_OLDOF(size()); + auto c = boost::contract::public_function(this) + .precondition([&] { + BOOST_CONTRACT_ASSERT(this->size() < max_size()); + }) + .postcondition([&] { + // Check this only if T has operator== (otherwise always true). + BOOST_CONTRACT_ASSERT( + boost::contract::call_if >( + boost::bind(std::equal_to(), boost::cref(back()), + boost::cref(value)) + ).else_([] { return true; }) + ); + + BOOST_CONTRACT_ASSERT(this->size() == *old_size + 1); + }) + ; + + vect_.push_back(value); + } + + /* ... */ +//] + + void invariant() const { + BOOST_CONTRACT_ASSERT(size() <= max_size()); + } + +private: + std::vector vect_; +}; + diff --git a/example/features/inc.cpp b/example/features/free_function.cpp similarity index 96% rename from example/features/inc.cpp rename to example/features/free_function.cpp index 1e69088..1139e9c 100644 --- a/example/features/inc.cpp +++ b/example/features/free_function.cpp @@ -1,5 +1,5 @@ -//[inc +//[free_function #include int inc(int& x) { diff --git a/example/features/push_back.cpp b/example/features/introduction.cpp similarity index 91% rename from example/features/push_back.cpp rename to example/features/introduction.cpp index a27c84c..89980a3 100644 --- a/example/features/push_back.cpp +++ b/example/features/introduction.cpp @@ -9,7 +9,7 @@ template class pushable; -//[push_back +//[introduction #include #include #include @@ -24,7 +24,7 @@ public: #undef BASES void invariant() const { // Checked in AND with base class invariants. - BOOST_CONTRACT_ASSERT(size() <= capacity()); + BOOST_CONTRACT_ASSERT(size() <= capacity()); // Line 27. } virtual void push_back(T const& value, boost::contract::virtual_* v = 0) @@ -33,10 +33,10 @@ public: auto c = boost::contract::public_function( v, &vector::push_back, this, value) .precondition([&] { // Checked in OR with base preconditions. - BOOST_CONTRACT_ASSERT(size() < max_size()); + BOOST_CONTRACT_ASSERT(size() < max_size()); // Line 36. }) .postcondition([&] { // Checked in AND with base postconditions. - BOOST_CONTRACT_ASSERT(size() == *old_size + 1); + BOOST_CONTRACT_ASSERT(size() == *old_size + 1); // Line 39. }) ; diff --git a/example/features/named_override.cpp b/example/features/named_override.cpp new file mode 100644 index 0000000..5e9a18b --- /dev/null +++ b/example/features/named_override.cpp @@ -0,0 +1,21 @@ + +//[named_override +class a + #define BASES public b + : BASES +{ +public: + typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types; + #undef BASES + + void _f(boost::contract::virtual_* v = 0) /* override */ { + auto c = boost::contract::public_function( + v, &a::_f, this) + /* ... */ + ; + } + BOOST_CONTRACT_NAMED_OVERRIDE(override_underscore_f, _f) // Explicit name. +}; +//] + + diff --git a/example/features/inc_no_contract.cpp b/example/features/no_contracts.cpp similarity index 90% rename from example/features/inc_no_contract.cpp rename to example/features/no_contracts.cpp index 26cf236..e2d7775 100644 --- a/example/features/inc_no_contract.cpp +++ b/example/features/no_contracts.cpp @@ -1,5 +1,5 @@ -//[inc_no_contract +//[no_contracts int inc(int& x) // Precondition: x < std::numeric_limits::max() // Postcondition: x == oldof(x) + 1 diff --git a/example/features/no_lambdas.cpp b/example/features/no_lambdas.cpp new file mode 100644 index 0000000..a3d14d8 --- /dev/null +++ b/example/features/no_lambdas.cpp @@ -0,0 +1,63 @@ + +#include "separate_body.hpp" + +//[no_lambdas_cpp +template +int array::instances_ = 0; + +template +array::array(std::size_t count) : + boost::contract::constructor_precondition( + &array::constructor_precondition), + values_(new T[MaxSize]) // Member initialization can be here. +{ + boost::shared_ptr old_instances; + auto c = boost::contract::constructor(this) + .old(boost::bind(&array::constructor_old, boost::ref(old_instances)) + .postcondition(boost::bind(&array::constructor_postcondition, this)) + ; + + for(std::size_t i = 0; i < count; ++i) values_[i] = T(); + size_ = count; + ++instances_; +} + +template +array::~array() { + boost::shared_ptr old_instances; + auto c = boost::contract::destructor(this) + .old(boost::bind(&array::destructor_old, boost::ref(old_instances)) + .postcondition(&array::destructor_postcondition) + ; + + delete[] values_; + --instances_; +} + +template +void array::push_back_body(T const& value) { + boost::shared_ptr old_size; + auto c = boost::contract::public_function(v, this) + .precondition(boost::bind(&array::push_back_precondition, + this, boost::cref(value))) + .old(boost::bind(&array::push_back_old, this, boost::ref(old_size)) + .postcondition(boost::bind(&array::push_back_postcondition, + this, boost::cref(value), old_size)) + ; + + values_[size_++] == value; +} + +template +std::size_t array::size_body() const { + auto c = boost::contract::public_function(this); // Check invariants. + return size_; +} + +template +int array::instance() { + auto c = boost::contract::public_function(); // Check invariants. + return instances_; +} +//] + diff --git a/example/features/no_lambdas.hpp b/example/features/no_lambdas.hpp new file mode 100644 index 0000000..494171d --- /dev/null +++ b/example/features/no_lambdas.hpp @@ -0,0 +1,64 @@ + +#include + +//[no_lambdas_hpp +template +class array + : private boost::contract::constructor_precondition > +{ +public: + void invariant() const { + BOOST_CONTRACT_ASSERT(size() <= MaxSize); + } + static void static_invariant() const { + BOOST_CONTRACT_ASSERT(instances() >= 0); + } + + explicit array(std::size_t count); + static void constructor_precondition(std::size_t const& count) { + BOOST_CONTRACT_ASSERT(count <= MaxSize) + } + static void constructor_old( + boost::shared_ptr& old_instances) { + old_instances = BOOST_CONTRACT_OLDOF(instances()); + } + void constructor_postcondition(std::size_t const& count, + boost::shared_ptr old_instances) const { + BOOST_CONTRACT_ASSERT(size() == count); + BOOST_CONTRACT_ASSERT(instances() == *old_instances + 1); + } + + virtual ~array(); + void destructor_old( + boost::shared_ptr& old_instances) const { + old_instances = BOOST_CONTRACT_OLDOF(instances()); + } + static void destructor_postcondition( + boost::shared_ptr old_instances) { + BOOST_CONTRACT_ASSERT(instances() == *old_instances - 1); + } + + void push_back(T const& value); + void push_back_precondition(T const& value) const { + BOOST_CONTRACT_ASSERT(size() < MaxSize); + } + void push_back_old(boost::shared_ptr& old_size) + const { + old_size = BOOST_CONTRACT_OLDOF(size()); + } + void push_back_postcondition(T const& value, + boost::shared_ptr old_size) const { + BOOST_CONTRACT_ASSERT(size() == *old_size + 1); + } + + std::size_t size() const; // Check invariants. + + static int instances(); // Check invariants. + +private: + T* values_; + std::size_t size_; + static int instances_; +}; +//] + diff --git a/example/features/no_macros.cpp b/example/features/no_macros.cpp new file mode 100644 index 0000000..ff7da84 --- /dev/null +++ b/example/features/no_macros.cpp @@ -0,0 +1,77 @@ + +//[no_oldof_macro +template +class vector { +public: + void push_back(T const& value, boost::contract::virtual_* v = 0) + // Program old-value without macros (pass extra `v` if virtual). + boost::shared_ptr old_size = + boost::contract::copy_old() ? size() : boost::contract::old(); + + auto c = boost::contract::public_function(this) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(size() == *old_size + 1); + }) + ; + + vect_.push_back(id); // Function body. + } + + /* ... */ + + //] + + void invariant() const { + BOOST_CONTRACT_ASSERT(size() >= 0); + } + +private: + std::vector vect_; +}; + +//[no_virtual_oldof_macro +class identifiers { +public: + virtual void push_back(int id, boost::contract::virtual_* v = 0) + // Program old-value without macros with extra `v`. + boost::shared_ptr old_size = + boost::contract::copy_old(v) ? size() : boost::contract::old(); + + auto c = boost::contract::public_function(this) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(size() == *old_size + 1); + }) + ; + + vect_.push_back(id); // Function body. + } + + /* ... */ + + //] + + void invariant() const { + BOOST_CONTRACT_ASSERT(size() >= 0); + } + +private: + std::vector vect_; +}; + + +//[no_base_types_macro +#include + +class multi_identifiers : + private boost::contract::constructor_precondition, + public identifiers, public virtual pushable, + protected sizer, private capacitor +{ +public: + // Program `base_types` without macros (list only public bases). + typedef boost::mpl::vector base_types; + + /* ... */ +//] +}; + diff --git a/example/features/override_trait.cpp b/example/features/override_trait.cpp deleted file mode 100644 index 57bfcf4..0000000 --- a/example/features/override_trait.cpp +++ /dev/null @@ -1,19 +0,0 @@ - -//[override_trait -class a - #define BASES public b - : BASES -{ -public: - typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types; - #undef BASES - - void _f(boost::contract::virtual_* v = 0) /* override */ { - auto c = boost::contract::public_function(v, &a::_f, this); - /* ... */ - } - BOOST_CONTRACT_OVERRIDE_TRAIT(override_f, _f) -}; -//] - - diff --git a/example/features/countdown.cpp b/example/features/private_protected.cpp similarity index 97% rename from example/features/countdown.cpp rename to example/features/private_protected.cpp index 94e9cc7..4044335 100644 --- a/example/features/countdown.cpp +++ b/example/features/private_protected.cpp @@ -1,5 +1,5 @@ -//[countdown +//[private_protected template class countdwon { public: diff --git a/example/features/identifiers.cpp b/example/features/public.cpp similarity index 95% rename from example/features/identifiers.cpp rename to example/features/public.cpp index 031bcac..639fa6a 100644 --- a/example/features/identifiers.cpp +++ b/example/features/public.cpp @@ -1,6 +1,6 @@ // Vector of unique integer numbers. -//[unique_identifiers_constructor +//[public_constructor // An identifier can be pushed only once in this container. class unique_identifiers : private boost::contract::constructor_precondition @@ -26,7 +26,7 @@ public: /* ... */ //] - //[unique_identifiers_destructor + //[public_destructor // Destroy this container. virtual ~unique_identifiers() { auto c = boost::contract::destructor(this); // Check invariants. @@ -39,7 +39,7 @@ public: return vect_.size(); } - //[unique_identifiers_find + //[public_function // Check if specified identifier is in container. bool find(int id) const { bool result; @@ -55,7 +55,7 @@ public: } //] - //[unique_identifiers_push_back + //[public_virtual_function // Specified identifier must not already be in container. virtual int push_back(int id, boost::contract::virtual_* v = 0) { int result; @@ -88,7 +88,7 @@ private: std::vector vect_; }; -//[identifiers_push_back +//[public_override_function // Can push same identifier multiple times in container (but with no effect). class identifiers #define BASES public unique_identifiers @@ -134,7 +134,7 @@ public: } }; -//[multi_identifiers +//[public_base_types class multi_identifiers #define BASES \ private boost::contract::constructor_precondition, \ diff --git a/example/features/separate_body.cpp b/example/features/separate_body.cpp index 031bcac..ffaaa45 100644 --- a/example/features/separate_body.cpp +++ b/example/features/separate_body.cpp @@ -1,152 +1,20 @@ -// Vector of unique integer numbers. -//[unique_identifiers_constructor -// An identifier can be pushed only once in this container. -class unique_identifiers - : private boost::contract::constructor_precondition -{ -public: +#include "separate_body.hpp" - // Create this container with all identifiers in range [from, to]. - unqiue_identifiers(int from, int to) : - boost::contract::constructor_precondition([&] { - BOOST_CONTRACT_ASSERT(from <= to); - }) - { - auto c = boost::contract::constructor(this) - .postcondition([&] { - BOOST_CONTRACT_ASSERT(size() == (to - from)); - }) - ; +//[separate_body_cpp +template +void array::constructor_body(std::size_t count) { + for(std::size_t i = 0; i < count; ++i) values_[i] = T(); + size_ = count; +} - // Constructor body. - for(id = from; id <= to; ++id) vect_.push_back(id); - } +template +void array::destructor_body() { delete[] values_; } - /* ... */ -//] - - //[unique_identifiers_destructor - // Destroy this container. - virtual ~unique_identifiers() { - auto c = boost::contract::destructor(this); // Check invariants. - // Destructor body here... - } - //] +template +std::size_t array::size_body() const { return size_; } - int size() const { - auto c = boost::contract::public_function(this); // Check invariants. - return vect_.size(); - } - - //[unique_identifiers_find - // Check if specified identifier is in container. - bool find(int id) const { - bool result; - auto c = boost::contract::public_function(this) - .postcondition([&] { - if(size() == 0) BOOST_CONTRACT_ASSERT(!result); - }) - ; - - // Function body. - return result = std::find(vect_.begin(), vect_.end(), id) != - vect_.end(); - } - //] - - //[unique_identifiers_push_back - // Specified identifier must not already be in container. - virtual int push_back(int id, boost::contract::virtual_* v = 0) { - int result; - auto old_find = BOOST_CONTRACT_OLDOF(v, find(id)); - auto old_size = BOOST_CONTRACT_OLDOF(v, size()); - auto c = boost::contract::public_function(v, result, this) - .precondition([&] { - BOOST_CONTRACT_ASSERT(!find(id)); // Already in, not allowed. - }) - .postcondition([&] (int result) { - if(!*old_find) { // Pushed in container. - BOOST_CONTRACT_ASSERT(find(id)); - BOOST_CONTRACT_ASSERT(size() == *old_size + 1); - } - BOOST_CONTRACT_ASSERT(result == id); - }) - ; - - // Function body. - vect_.push_back(id); - return result = id; - } - //] - - void invariant() const { - BOOST_CONTRACT_ASSERT(size() >= 0); - } - -private: - std::vector vect_; -}; - -//[identifiers_push_back -// Can push same identifier multiple times in container (but with no effect). -class identifiers - #define BASES public unique_identifiers - : BASES -{ -public: - typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types; - #undef BASES - - void invariant() const { // Check in AND with bases. - BOOST_CONTRACT_ASSERT(empty() == (size() == 0)); - } - - // Do nothing if specified identifier already in container. - int push_back(int id, boost::contract::virtual_* v = 0) /* override */ { - int result; - auto old_find = BOOST_CONTRACT_OLDOF(v, find(id)); - auto old_size = BOOST_CONTRACT_OLDOF(v, size()); - auto c = boost::contract::public_function( - v, result, &identifiers::push_back, this, id) - .precondition([&] { // Check in OR with bases. - BOOST_CONTRACT_ASSERT(find(id)); // Already in, now allowed. - }) - .postcondition([&] (int result) { // Check in AND with bases. - if(*old_find) { // Not added. - BOOST_CONTRACT_ASSERT(size() == *old_size); - } - }) - ; - - // Function body. - if(!find(id)) unique_identifiers::push_back(id); // Else, do nothing. - return result = id; - } - BOOST_CONTRACT_OVERRIDE(push_back); // Define `override_push_back`. - - /* ... */ +template +void array::push_back_body(T const& value) { values_[size_++] == value; } //] - bool empty() const { - auto c = boost::contract::public_function(this); // Check invariants. - return size() == 0; - } -}; - -//[multi_identifiers -class multi_identifiers - #define BASES \ - private boost::contract::constructor_precondition, \ - public identifiers, public virtual pushable, \ - protected sizer, private capacitor - : BASES -{ -public: - typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types; - #undef BASES - - /* ... */ -//] -}; - diff --git a/example/features/separate_body.hpp b/example/features/separate_body.hpp new file mode 100644 index 0000000..635d47d --- /dev/null +++ b/example/features/separate_body.hpp @@ -0,0 +1,62 @@ + +#include + +//[separate_body_hpp +template +class array + : private boost::contract::constructor_precondition +{ +public: + void invariant() const { + BOOST_CONTRACT_ASSERT(size() <= MaxSize); + } + + explicit array(std::size_t count) : + boost::contract::constructor_precondition([&] { + BOOST_CONTRACT_ASSERT(count <= MaxSize) + }), + values_(new T[MaxSize]) // But must member initializations here. + { + auto c = boost::contract::constructor(this) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(size() == count); + }) + ; + constructor_body(count); + } + + virtual ~array() { + auto c = boost::contract::destructor(this); // Check invariants. + destructor_body(); + } + + std::size_t size() const { + auto c = boost::contract::public_function(this); // Check invariants. + return size_body(); + } + + void push_back(T const& value) { + auto old_size = BOOST_CONTRACT_OLDOF(v, size()); + auto c = boost::contract::public_function(v, this) + .precondition([&] { + BOOST_CONTRACT_ASSERT(size() < MaxSize); + }) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(size() == *old_size + 1); + }) + ; + push_back_body(); + } + +private: + // Contracts in class declaration (above), but body implementations are not. + void construtor_body(std::size_t count); + void destructor_body(); + std::size_t size_body() const; + void push_back_body(T const& value); + + T* values_; + std::size_t size_; +}; +//] + diff --git a/example/features/static.cpp b/example/features/static.cpp index d7f4ac1..f67e63f 100644 --- a/example/features/static.cpp +++ b/example/features/static.cpp @@ -3,47 +3,47 @@ //[static template -class instance_counter { +class make { public: static void static_invariant() { // Static class invariants. - BOOST_CONTRACT_ASSERT(count() >= 0); + BOOST_CONTRACT_ASSERT(instances() >= 0); } - static int count() { // Static public function (check static invariants). - auto c = boost::contract::public_function(); - return count_; // Function body. + static int instances() { + auto c = boost::contract::public_function(); // Check invariants. + return instances_; // Function body. } - instance_counter() : obj_() { - auto old_count = BOOST_CONTRACT_OLDOF(count()); + make() : obj_() { + auto old_instances = BOOST_CONTRACT_OLDOF(instances()); auto c = boost::contract::constructor(this) .postcondition([&] { - BOOST_CONTRACT_OLDOF(count() == *old_count + 1); + BOOST_CONTRACT_OLDOF(instances() == *old_instances + 1); }) ; - ++count_; + ++instances_; } - ~instance_counter() { - auto old_count = BOOST_CONTRACT_OLDOF(count()); + ~make() { + auto old_instances = BOOST_CONTRACT_OLDOF(instances()); auto c = boost::contract::destructor(this) .postcondition([&] { // (An example of destructor postconditions.) - BOOST_CONTRACT_OLDOF(count() == *old_count - 1); + BOOST_CONTRACT_OLDOF(instances() == *old_instances - 1); }) ; - --count_; + --instances_; } /* ... */ private: C obj_; - static int count_; + static int instances_; }; template -int instance_counter::count_ = 0; +int make::instances_ = 0; //] diff --git a/example/features/static_if_cxx14.cpp b/example/features/static_if_cxx14.cpp new file mode 100644 index 0000000..f8a5d42 --- /dev/null +++ b/example/features/static_if_cxx14.cpp @@ -0,0 +1,110 @@ + +// Test possible impl. advance() in single function with C++14 generic lambdas. + +#include +#include +#include +#include +#include // std::bind for generic lambdas. +#include +#include +#include + +template +struct is_random_access_iterator : std::is_same< + typename std::iterator_traits::iterator_category, + std::random_access_iterator_tag +> {}; + +template +struct is_bidirectional_iterator : std::is_same< + typename std::iterator_traits::iterator_category, + std::bidirectional_iterator_tag +> {}; + +template +struct is_input_iterator : std::is_same< + typename std::iterator_traits::iterator_category, + std::input_iterator_tag +> {}; + +//[static_if_cxx14 +template +void myadvance(Iter& i, Dist n) { + Iter *p = &i; // So captures change actual pointed iterator value. + boost::contract::call_if >( + std::bind([] (auto p, auto n) { + *p += n; + }, p, n) + ).template else_if >( + std::bind([] (auto p, auto n) { + if(n >= 0) while(n--) ++*p; + else while(n++) --*p; + }, p, n) + ).template else_if >( + std::bind([] (auto p, auto n) { + while(n--) ++*p; + }, p, n) + ).else_( + std::bind([] (auto false_) { + static_assert(false_, "requires input iter"); + }, std::false_type()) // Use constexpr value. + ); +} +//] + +struct x {}; // Test not an iterator (static_assert failure in else_ above). + +namespace std { + template<> + struct iterator_traits { + typedef void iterator_category; + }; +} + +int main() { + std::ostringstream ok; + + std::vector v; + v.push_back('a'); + v.push_back('b'); + v.push_back('c'); + v.push_back('d'); + std::vector::iterator r = v.begin(); // Random iterator. + out.str(""); + myadvance(r, 1); + out << *r << std::endl; + ok.str(""); ok + << "random iterator" << std::endl + << "b" << std::endl + ; + BOOST_TEST(out.eq(ok.str())); + + std::list l(v.begin(), v.end()); + std::list::iterator b = l.begin(); // Bidirectional iterator. + out.str(""); + myadvance(b, 2); + out << *b << std::endl; + ok.str(""); ok + << "bidirectional iterator" << std::endl + << "c" << std::endl + ; + BOOST_TEST(out.eq(ok.str())); + + std::istringstream s("a b c d"); + std::istream_iterator i(s); + out.str(""); + myadvance(i, 3); + out << *i << std::endl; + ok.str(""); ok + << "input iterator" << std::endl + << "d" << std::endl + ; + BOOST_TEST(out.eq(ok.str())); + + // x xx; + // myadvance(xx, 0); // Error (correctly because x not even input iter). + + return boost::report_errors(); +} + diff --git a/example/features/throw_on_failure.cpp b/example/features/throw_on_failure.cpp new file mode 100644 index 0000000..4eb41f1 --- /dev/null +++ b/example/features/throw_on_failure.cpp @@ -0,0 +1,99 @@ + +#include +#include +#include +#include + +//[throw_on_failure_cstring +struct too_large_error {}; + +template +class cstring + #define BASES private boost::contract::constructor_precondition< \ + cstring > + : BASES +{ +public: + typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types; + #undef BASES + + /* implicit */ cstring(char const* chars) : + boost::contract::constructor_precondition([&] { + BOOST_CONTRACT_ASSERT(chars); // Throw `assertion_failure`. + if(std::strlen(chars) > MaxSize) { + throw too_large_error(); // Also throw user-defined exception. + } + }) + { + auto c = boost::contract::constructor(this) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(size() == std::strlen(chars)); + }) + ; + + size_ = std::strlen(chars); + for(int i = 0; i < size_; ++i) chars_[i] = chars[i]; + chars_[size_] = '\0'; + } + + /* ... */ +//] + + ~string() { + auto c = boost::contract::destructor(this); // Check invariants. + delete[] chars_; + } + + int size() const { + auto c = boost::contract::public_function(this); // Check invariants. + return size_; + } + + void invariant() const { + BOOST_CONTRACT_ASSERT(size() < MaxSize); + BOOST_CONTRACT_ASSERT(chars_); + BOOST_CONTRACT_ASSERT(chars_[size()] == '\0'); + } + +private: + char[MaxSize] chars_; + std::size_t size_; +}; + +//[throw_on_failure_handler +void throwing_handler(boost::contract::from context) { + if(context == boost::contract::from_destructor) { + // Ignore exception because destructors should never throw. + std::cerr << "destructor contract failed (ignored)" << std::endl; + } else { + throw; // Re-throw (assertion_failure, too_large_error, etc.). + } +} + +int main() { + boost::contract::set_precondition_failed(&throwing_handler); + boost::contract::set_postcondition_failed(&throwing_handler); + boost::contract::set_invariant_failed(&throwing_handler); + + /* ... */ +//] + + string s("abc"); + BOOST_TEST_EQ(s[0], 'a'); + + bool pass = false; + try { + std::cout << "1" << std::endl; + s[3]; + std::cout << "2" << std::endl; + } // Out of range. + catch(string::range_error const&) { + std::cout << "3" << std::endl; + pass = true; + } + std::cout << "4" << std::endl; + BOOST_TEST(pass); + + return boost::report_errors(); +} + diff --git a/example/mitchell02/counter/counter.hpp b/example/mitchell02/counter/counter.hpp index 771896d..53779c3 100644 --- a/example/mitchell02/counter/counter.hpp +++ b/example/mitchell02/counter/counter.hpp @@ -1,4 +1,5 @@ +//[mitchell02_counter #ifndef COUNTER_HPP_ #define COUNTER_HPP_ @@ -55,4 +56,5 @@ private: }; #endif // #include guard +//] diff --git a/example/mitchell02/counter/decrement_button.hpp b/example/mitchell02/counter/decrement_button.hpp index f09f3c7..1c4b097 100644 --- a/example/mitchell02/counter/decrement_button.hpp +++ b/example/mitchell02/counter/decrement_button.hpp @@ -1,4 +1,5 @@ +//[mitchell02_decrement_button #ifndef DECREMENT_BUTTON_HPP_ #define DECREMENT_BUTTON_HPP_ @@ -78,4 +79,5 @@ private: }; #endif // #include guard +//] diff --git a/example/mitchell02/counter/push_button.hpp b/example/mitchell02/counter/push_button.hpp index 0bec023..906a59e 100644 --- a/example/mitchell02/counter/push_button.hpp +++ b/example/mitchell02/counter/push_button.hpp @@ -1,4 +1,5 @@ +//[mitchell02_push_button #ifndef PUSH_BUTTON_HPP_ #define PUSH_BUTTON_HPP_ @@ -68,4 +69,5 @@ void push_button::on_bn_clicked(boost::contract::virtual_* v) { } #endif // #include guard +//] diff --git a/example/mitchell02/counter_main.cpp b/example/mitchell02/counter_main.cpp index db53548..1f7185a 100644 --- a/example/mitchell02/counter_main.cpp +++ b/example/mitchell02/counter_main.cpp @@ -1,4 +1,5 @@ +//[mitchell02_counter_main #include "counter/counter.hpp" #include "counter/decrement_button.hpp" #include "observer/observer.hpp" @@ -65,4 +66,5 @@ int main() { return boost::report_errors(); } +//] diff --git a/example/mitchell02/courier.cpp b/example/mitchell02/courier.cpp index fb43528..01955d0 100644 --- a/example/mitchell02/courier.cpp +++ b/example/mitchell02/courier.cpp @@ -1,4 +1,5 @@ +//[mitchell02_courier #include #include #include @@ -187,4 +188,5 @@ int main() { return boost::report_errors(); } +//] diff --git a/example/mitchell02/customer_manager.cpp b/example/mitchell02/customer_manager.cpp index 385ff55..4c76765 100644 --- a/example/mitchell02/customer_manager.cpp +++ b/example/mitchell02/customer_manager.cpp @@ -1,4 +1,5 @@ +//[mitchell02_customer_manager #include #include #include @@ -123,4 +124,5 @@ int main() { return boost::report_errors(); } +//] diff --git a/example/mitchell02/dictionary.cpp b/example/mitchell02/dictionary.cpp index 7b7228d..e1f0b04 100644 --- a/example/mitchell02/dictionary.cpp +++ b/example/mitchell02/dictionary.cpp @@ -1,4 +1,5 @@ +//[mitchell02_dictionary #include #include #include @@ -114,4 +115,5 @@ int main() { return boost::report_errors(); } +//] diff --git a/example/mitchell02/name_list.cpp b/example/mitchell02/name_list.cpp index bbf2370..9a02582 100644 --- a/example/mitchell02/name_list.cpp +++ b/example/mitchell02/name_list.cpp @@ -1,4 +1,5 @@ +//[mitchell02_name_list #include #include #include @@ -124,4 +125,5 @@ int main() { return boost::report_errors(); } +//] diff --git a/example/mitchell02/observer/observer.hpp b/example/mitchell02/observer/observer.hpp index 9ed7f7c..dad63c3 100644 --- a/example/mitchell02/observer/observer.hpp +++ b/example/mitchell02/observer/observer.hpp @@ -1,4 +1,5 @@ +//[mitchell02_observer #ifndef OBSERVER_HPP_ #define OBSERVER_HPP_ @@ -42,4 +43,5 @@ void observer::update(boost::contract::virtual_* v) { } #endif // #include guard +//] diff --git a/example/mitchell02/observer/subject.hpp b/example/mitchell02/observer/subject.hpp index 8c5409d..d42d290 100644 --- a/example/mitchell02/observer/subject.hpp +++ b/example/mitchell02/observer/subject.hpp @@ -1,4 +1,5 @@ +//[mitchell02_subject #ifndef SUBJECT_HPP_ #define SUBJECT_HPP_ @@ -157,4 +158,5 @@ private: }; #endif // #include guard +//] diff --git a/example/mitchell02/observer_main.cpp b/example/mitchell02/observer_main.cpp index 93e452b..d458d97 100644 --- a/example/mitchell02/observer_main.cpp +++ b/example/mitchell02/observer_main.cpp @@ -1,4 +1,5 @@ +//[mitchell02_observer_main #include "observer/observer.hpp" #include "observer/subject.hpp" #include @@ -94,4 +95,5 @@ int main() { return boost::report_errors(); } +//] diff --git a/example/mitchell02/simple_queue.cpp b/example/mitchell02/simple_queue.cpp index 0ba16e6..bbc649f 100644 --- a/example/mitchell02/simple_queue.cpp +++ b/example/mitchell02/simple_queue.cpp @@ -1,4 +1,5 @@ +//[mitchell02_simple_queue #include #include #include @@ -212,4 +213,5 @@ int main() { return boost::report_errors(); } +//] diff --git a/example/mitchell02/stack.cpp b/example/mitchell02/stack.cpp index d513dd5..4868d6f 100644 --- a/example/mitchell02/stack.cpp +++ b/example/mitchell02/stack.cpp @@ -1,4 +1,5 @@ +//[mitchell02_stack #include #include #include @@ -125,4 +126,5 @@ int main() { return boost::report_errors(); } +//] diff --git a/example/n1962/circle.cpp b/example/n1962/circle.cpp index 2539edf..db01984 100644 --- a/example/n1962/circle.cpp +++ b/example/n1962/circle.cpp @@ -1,4 +1,5 @@ +//[n1962_circle #include #include #include @@ -52,4 +53,5 @@ int main() { BOOST_TEST_EQ(c.compute_area(), 12); return boost::report_errors(); } +//] diff --git a/example/n1962/equal.cpp b/example/n1962/equal.cpp index cfa8ab6..b9cf03e 100644 --- a/example/n1962/equal.cpp +++ b/example/n1962/equal.cpp @@ -1,4 +1,5 @@ +//[n1962_equal #include #include @@ -41,4 +42,5 @@ int main() { return boost::report_errors(); } +//] diff --git a/example/n1962/factorial.cpp b/example/n1962/factorial.cpp index 0c2f57b..e270082 100644 --- a/example/n1962/factorial.cpp +++ b/example/n1962/factorial.cpp @@ -1,4 +1,5 @@ +//[n1962_factorial #include #include @@ -40,4 +41,5 @@ int main() { BOOST_TEST_EQ(factorial(4), 24); return boost::report_errors(); } +//] diff --git a/example/n1962/sqrt.cpp b/example/n1962/sqrt.cpp index e9ed204..9d3c090 100644 --- a/example/n1962/sqrt.cpp +++ b/example/n1962/sqrt.cpp @@ -1,4 +1,5 @@ +//[n1962_sqrt #include #include #include @@ -22,4 +23,5 @@ int main() { BOOST_TEST(fabs(mysqrt(4.0, precision) - 2.0) <= precision); return boost::report_errors(); } +//] diff --git a/example/n1962/sqrt.d b/example/n1962/sqrt.d index 0dba6d5..9fe53d9 100644 --- a/example/n1962/sqrt.d +++ b/example/n1962/sqrt.d @@ -1,13 +1,6 @@ -// Copyright (C) 2008-2012 Lorenzo Caminiti -// Use, modification, and distribution is subject to 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). -// Documentation at http://contractpp.sourceforge.net. - //[n1962_sqrt_d -// File: sqrt.d -// Extra spaces, newlines, etc used to align text with this library code. +// Extra newlines, etc. used to align text with this library code. diff --git a/example/n1962/sum.cpp b/example/n1962/sum.cpp index 3c71c90..19ae894 100644 --- a/example/n1962/sum.cpp +++ b/example/n1962/sum.cpp @@ -1,4 +1,5 @@ +//[n1962_sum #include #include @@ -20,4 +21,5 @@ int main() { BOOST_TEST_EQ(sum(4, a), 10); return boost::report_errors(); } +//] diff --git a/example/n1962/vector.cpp b/example/n1962/vector.cpp index 80283e3..0311a13 100644 --- a/example/n1962/vector.cpp +++ b/example/n1962/vector.cpp @@ -1,4 +1,5 @@ +//[n1962_vector #include #include #include @@ -664,4 +665,5 @@ int main() { return boost::report_errors(); } +//] diff --git a/example/n1962/vector_n1962.cpp b/example/n1962/vector_n1962.hpp similarity index 98% rename from example/n1962/vector_n1962.cpp rename to example/n1962/vector_n1962.hpp index 287df85..15dfd3d 100644 --- a/example/n1962/vector_n1962.cpp +++ b/example/n1962/vector_n1962.hpp @@ -5,9 +5,8 @@ // http://www.boost.org/LICENSE_1_0.txt) // Home at http://sourceforge.net/projects/contractpp -//[n1962_vector_npaper -// File: vector_npaper.cpp -// Extra spaces, newlines, etc used to align text with this library code. +//[n1962_vector_n1962 +// Extra newlines, etc. used to align text with this library code. #include #include diff --git a/example/stroustrup97/string.cpp b/example/stroustrup97/string.cpp index 95570a2..609e608 100644 --- a/example/stroustrup97/string.cpp +++ b/example/stroustrup97/string.cpp @@ -1,8 +1,10 @@ +//[stroustrup97_string #include #include #include #include +#include // Adapted from an example presented in the book "The C++ Programming Language" // (Stroustrup, 1997) to illustrate importance of class invariants. Simple @@ -123,4 +125,5 @@ int main() { return boost::report_errors(); } +//] diff --git a/features.txt b/features.txt index 9205941..78855db 100644 --- a/features.txt +++ b/features.txt @@ -74,4 +74,9 @@ x Old values with/without subcontracting * What shall I do with unions... can/shall I contract them? Check-out which members C++11 unions can have (ctors, dtor, etc.) * Make work the case a pure virtual uses boost::optional result but an overriding function uses just T result, and the other way around too. +* What happens to OLDOF and related assertions if old-of expression type T does not have a copy constructor? ...maybe just mention that these cases are rare... and they can be handled with call_if and C++14 lambdas, or writing verbose functors even without C++14... +* Figure out correct impl of volatile class invariants... +* Test OLDOF for non-copy-constructible types. In this case OLDOF (and old) could just skip the copy leaving the pointer to be null. Then programmers could check if the old-value pointer is null so skip evaluating its assertion in postconditions... this seems a simple and elegant solution (without having to use call_if, bind, etc. here). C++11 std::is_copy_constructible could be used, but maybe still be wrapped within a boost::contract::has_oldof trait so to work on C++03 via user specializations... + Hhmmm... but this will not allow programmers to force compilation to fail in case the old value expr is not copyable... that's not good then. +* Test what happens if bodies throw (e.g., public func should check inv, dtor too, but ctor not, etc.) diff --git a/include/boost/contract/core/exception.hpp b/include/boost/contract/core/exception.hpp index c80d278..cf1441d 100644 --- a/include/boost/contract/core/exception.hpp +++ b/include/boost/contract/core/exception.hpp @@ -103,6 +103,7 @@ namespace exception_ { } catch(boost::contract::assertion_failure const& error) { // what = 'assertion "..." failed: ...'. std::cerr << s << error.what() << std::endl; + // TODO: Below, I should use Boost.Exception diagnostic message... } catch(std::exception const& error) { std::cerr << s << "checking threw standard exception with " << "what(): " << error.what() << std::endl; diff --git a/test/call_if/advance_cxx14.cpp b/test/call_if/advance_cxx14.cpp index 40d5797..fde0b52 100644 --- a/test/call_if/advance_cxx14.cpp +++ b/test/call_if/advance_cxx14.cpp @@ -33,9 +33,8 @@ struct is_input_iterator : std::is_same< template void myadvance(Iter& i, Dist n) { - using boost::contract::call_if; Iter *p = &i; // So captures change actual pointed iterator value. - call_if >( + boost::contract::call_if >( std::bind([] (auto p, auto n) { out << "random iterator" << std::endl; *p += n;