Imported Upstream version 1.72.0
[platform/upstream/boost.git] / boost / contract / call_if.hpp
1
2 #ifndef BOOST_CONTRACT_CALL_IF_HPP_
3 #define BOOST_CONTRACT_CALL_IF_HPP_
4
5 // Copyright (C) 2008-2018 Lorenzo Caminiti
6 // Distributed under the Boost Software License, Version 1.0 (see accompanying
7 // file LICENSE_1_0.txt or a copy at http://www.boost.org/LICENSE_1_0.txt).
8 // See: http://www.boost.org/doc/libs/release/libs/contract/doc/html/index.html
9
10 /** @file
11 Statically disable compilation and execution of functor calls.
12
13 @note   These facilities allow to emulate C++17 <c>if constexpr</c> statements
14         when used together with functor templates (and C++14 generic lambdas).
15         Therefore, they are not useful on C++17 compilers where
16         <c> if constexpr</c> can be directly used instead.
17 */
18
19 #include <boost/contract/detail/none.hpp>
20 #include <boost/make_shared.hpp>
21 #include <boost/shared_ptr.hpp>
22 #include <boost/utility/enable_if.hpp>
23 #include <boost/config.hpp>
24
25 /* PRIVATE */
26
27 /** @cond */
28
29 // Boost.ResultOf not always able to deduce lambda result type (on MSVC).
30 #ifndef BOOST_NO_CXX11_DECLTYPE
31     #include <boost/utility/declval.hpp>
32     #define BOOST_CONTRACT_CALL_IF_RESULT_OF_(F) \
33         decltype(boost::declval<F>()())
34 #else
35     #include <boost/utility/result_of.hpp>
36     #define BOOST_CONTRACT_CALL_IF_RESULT_OF_(F) \
37         typename boost::result_of<F()>::type
38 #endif
39
40 /** @endcond */
41
42 /* CODE */
43
44 namespace boost { namespace contract {
45
46 /**
47 Select compilation and execution of functor template calls using a static
48 boolean predicate (not needed on C++17 compilers, use <c>if constexpr</c>
49 instead).
50
51 This class template has no members because it is never used directly, it is only
52 used via its specializations.
53 Usually this class template is instantiated only via the return value of
54 @RefFunc{boost::contract::call_if} and @RefFunc{boost::contract::call_if_c}.
55
56 @see    @RefSect{extras.assertion_requirements__templates_,
57         Assertion Requirements}
58
59 @tparam Pred    Static boolean predicate that selects which functor template
60                 call to compile and execute.
61 @tparam Then Type of the functor template to call if the static predicate
62         @c Pred is @c true.
63 @tparam ThenResult Return type of then-branch functor template call (this is
64         usually automatically deduced by this library so it is never explicitly
65         specified by the user, and that is why it is often marked as
66         @c internal_type in this documentation).
67 */
68 template<bool Pred, typename Then, typename ThenResult =
69     #ifndef BOOST_CONTRACT_DETAIL_DOXYGEN
70         boost::contract::detail::none
71     #else
72         internal_type
73     #endif
74 >
75 struct call_if_statement {}; // Empty so cannot be used (but copyable).
76
77 /**
78 Template specialization to dispatch between then-branch functor template calls
79 that return void and the ones that return non-void (not needed on C++17
80 compilers, use <c>if constexpr</c> instead).
81
82
83 The base class is a call-if statement so the else and else-if statements can be
84 specified if needed.
85 Usually this class template is instantiated only via the return value of
86 @RefFunc{boost::contract::call_if} and @RefFunc{boost::contract::call_if_c}.
87
88 @note   The <c>result_of<Then()>::type</c> expression needs be evaluated only
89         when the static predicate is already checked to be @c true (because
90         @c Then() is required to compile only in that case).
91         Thus, this template specialization introduces an extra level of
92         indirection necessary for proper lazy evaluation of this result-of
93         expression.
94
95 @see    @RefSect{extras.assertion_requirements__templates_,
96         Assertion Requirements}
97
98 @tparam Then Type of functor template to call when the static predicate is
99         @c true (as it is for this template specialization).
100 */
101 template<typename Then>
102 struct call_if_statement<true, Then,
103     #ifndef BOOST_CONTRACT_DETAIL_DOXYGEN
104         boost::contract::detail::none
105     #else
106         internal_type
107     #endif
108 > :
109     call_if_statement<true, Then,
110         #ifndef BOOST_CONTRACT_DETAIL_DOXYGEN
111             BOOST_CONTRACT_CALL_IF_RESULT_OF_(Then)
112         #else
113             typename result_of<Then()>::type
114         #endif
115     >
116 { // Copyable (as its base).
117     /**
118     Construct this object with the then-branch functor template.
119
120     @param f    Then-branch nullary functor template.
121                 The functor template call @c f() is compiled and called for this
122                 template specialization (because the if-statement static
123                 predicate is @c true).
124                 The return type of @c f() must be the same as (or implicitly
125                 convertible to) the return type of all other functor template
126                 calls specified for this call-if object.
127     */
128     explicit call_if_statement(Then f) : call_if_statement<true, Then,
129             BOOST_CONTRACT_CALL_IF_RESULT_OF_(Then)>(f) {}
130 };
131
132 /**
133 Template specialization to handle static predicates that are @c true for
134 then-branch functor template calls that do not return void (not needed on C++17
135 compilers, use <c>if constexpr</c> instead).
136
137
138 Usually this class template is instantiated only via the return value of
139 @RefFunc{boost::contract::call_if} and @RefFunc{boost::contract::call_if_c}.
140
141 @see    @RefSect{extras.assertion_requirements__templates_,
142         Assertion Requirements}
143
144 @tparam Then Type of functor template to call when the static predicate is
145         @c true (as it is for this template specialization).
146 @tparam ThenResult Non-void return type of the then-branch functor template
147         call.
148 */
149 template<typename Then, typename ThenResult>
150 struct call_if_statement<true, Then, ThenResult> { // Copyable (as *).
151     /**
152     Construct this object with the then-branch functor template.
153
154     @param f    Then-branch nullary functor template.
155                 The functor template call @c f() is actually compiled and
156                 executed for this template specialization (because the
157                 if-statement static predicate is @c true).
158                 The return type of @c f() must be the same as (or implicitly
159                 convertible to) the @p ThenResult type.
160     */
161     explicit call_if_statement(Then f) :
162             r_(boost::make_shared<ThenResult>(f())) {}
163
164     /**
165     This implicit type conversion returns a copy of the value returned by the
166     call to the then-branch functor template.
167     */
168     operator ThenResult() const { return *r_; }
169
170     /**
171     Specify the else-branch functor template.
172
173     @param f    Else-branch nullary functor template.
174                 The functor template call @c f() is never compiled or executed
175                 for this template specialization (because the if-statement
176                 static predicate is @c true).
177                 The return type of @c f() must be the same as (or implicitly
178                 convertible to) the @p ThenResult type.
179     
180     @return A copy of the value returned by the call to the then-branch functor
181             template (because the else-branch functor template call is not
182             executed).
183     */
184     template<typename Else>
185     ThenResult else_(Else const&
186         #ifdef BOOST_CONTRACT_DETAIL_DOXYGEN
187             f
188         #endif
189     ) const { return *r_; }
190     
191     /**
192     Specify an else-if-branch functor template (using a static boolean
193     predicate).
194
195     @param f    Else-if-branch nullary functor template.
196                 The functor template call @c f() is never compiled or executed
197                 for this template specialization (because the if-statement
198                 static predicate is @c true).
199                 The return type of @c f() must be the same as (or implicitly
200                 convertible to) the @p ThenResult type.
201     
202     @tparam ElseIfPred  Static boolean predicate selecting which functor
203                         template call to compile and execute.
204     
205     @return A call-if statement so the else statement and additional else-if
206             statements can be specified if needed.
207             Eventually, it will be the return value of the then-branch functor
208             template call for this template specialization (because the
209             if-statement static predicate is @c true).
210     */
211     template<bool ElseIfPred, typename ElseIfThen>
212     call_if_statement<true, Then, ThenResult> else_if_c(
213         ElseIfThen const&
214         #ifdef BOOST_CONTRACT_DETAIL_DOXYGEN // Avoid unused param warning.
215             f
216         #endif
217     ) const { return *this; }
218
219     /**
220     Specify an else-if-branch functor template (using a nullary boolean
221     meta-function).
222
223     @param f    Else-if-branch nullary functor template.
224                 The functor template call @c f() is never compiled or executed
225                 for this template specialization (because the if-statement
226                 static predicate is @c true).
227                 The return type of @c f() must be the same as (or implicitly
228                 convertible to) the @p ThenResult type.
229     
230     @tparam ElseIfPred  Nullary boolean meta-function selecting which functor
231                         template call to compile and execute.
232     
233     @return A call-if statement so the else statement and additional else-if
234             statements can be specified if needed.
235             Eventually, it will be the return value of the then-branch functor
236             template call for this template specialization (because the
237             if-statement static predicate is @c true).
238     */
239     template<class ElseIfPred, typename ElseIfThen>
240     call_if_statement<true, Then, ThenResult> else_if(
241         ElseIfThen const&
242         #ifdef BOOST_CONTRACT_DETAIL_DOXYGEN // Avoid unused param warning.
243             f
244         #endif
245     ) const { return *this; }
246     
247 private:
248     boost::shared_ptr<ThenResult> r_;
249 };
250
251 /**
252 Template specialization to handle static predicates that are @c true for
253 then-branch functor template calls that return void (not needed on C++17
254 compilers, use <c>if constexpr</c> instead).
255
256
257 Usually this class template is instantiated only via the return value of
258 @RefFunc{boost::contract::call_if} and @RefFunc{boost::contract::call_if_c}.
259
260 @see    @RefSect{extras.assertion_requirements__templates_,
261         Assertion Requirements}
262
263 @tparam Then Type of functor template to call when the static predicate if
264         @c true (as it is for this template specialization).
265 */
266 template<typename Then>
267 struct call_if_statement<true, Then, void> { // Copyable (no data).
268     /**
269     Construct this object with the then-branch functor template.
270
271     @param f    Then-branch nullary functor template.
272                 The functor template call @c f() is actually compiled and
273                 executed for this template specialization (because the
274                 if-statement static predicate is @c true).
275                 The return type of @c f() must be @c void for this template
276                 specialization (because the then-branch functor template calls
277                 return void).
278     */
279     explicit call_if_statement(Then f) { f(); }
280     
281     // Cannot provide `operator ThenResult()` here, because ThenResult is void.
282
283     /**
284     Specify the else-branch functor template.
285
286     @param f    Else-branch nullary functor template.
287                 The functor template call @c f() is never compiled or executed
288                 for this template specialization (because the if-statement
289                 static predicate is @c true).
290                 The return type of @c f() must be @c void for this template
291                 specialization (because the then-branch functor template calls
292                 return void).
293     */
294     template<typename Else>
295     void else_(Else const&
296         #ifdef BOOST_CONTRACT_DETAIL_DOXYGEN
297             f
298         #endif
299     ) const {}
300     
301     /**
302     Specify an else-if-branch functor template (using a static boolean
303     predicate).
304
305     @param f    Else-if-branch nullary functor template.
306                 The functor template call @c f() is never compiled or executed
307                 for this template specialization (because the if-statement
308                 static predicate is @c true).
309                 The return type of @c f() must be @c void for this template
310                 specialization (because the then-branch functor template calls
311                 return void).
312     
313     @tparam ElseIfPred  Static boolean predicate selecting which functor
314                         template call to compile and execute.
315     
316     @return A call-if statement so the else statement and additional else-if
317             statements can be specified if needed.
318             Eventually, it will return void for this template specialization
319             (because the then-branch functor template calls return void).
320     */
321     template<bool ElseIfPred, typename ElseIfThen>
322     call_if_statement<true, Then, void> else_if_c(
323         ElseIfThen const&
324         #ifdef BOOST_CONTRACT_DETAIL_DOXYGEN // Avoid unused param warning.
325             f
326         #endif
327     ) const { return *this; }
328
329     /**
330     Specify an else-if-branch functor template (using a nullary boolean
331     meta-function).
332
333     @param f    Else-if-branch nullary functor template.
334                 The functor template call @c f() is never compiled or executed
335                 for this template specialization (because the if-statement
336                 static predicate is @c true).
337                 The return type of @c f() must be @c void for this template
338                 specialization (because the then-branch functor template calls
339                 return void).
340
341     @tparam ElseIfPred  Nullary boolean meta-function selecting which functor
342                         template call to compile and execute.
343
344     @return A call-if statement so the else statement and additional else-if
345             statements can be specified if needed.
346             Eventually, it will return void for this template specialization
347             (because the then-branch functor template calls return void).
348     */
349     template<class ElseIfPred, typename ElseIfThen>
350     call_if_statement<true, Then, void> else_if(
351         ElseIfThen const&
352         #ifdef BOOST_CONTRACT_DETAIL_DOXYGEN // Avoid unused param warning.
353             f
354         #endif
355     ) const { return *this; }
356 };
357
358 /**
359 Template specialization to handle static predicates that are @c false (not
360 needed on C++17 compilers, use <c>if constexpr</c> instead).
361
362 This template specialization handles all else-branch functor template calls
363 (whether they return void or not).
364 Usually this class template is instantiated only via the return value of
365 @RefFunc{boost::contract::call_if} and @RefFunc{boost::contract::call_if_c}.
366
367 @see    @RefSect{extras.assertion_requirements__templates_,
368         Assertion Requirements}
369
370 @tparam Then Type of functor template to call when the static predicate is
371         @c true (never the case for this template specialization).
372 */
373 template<typename Then> // Copyable (no data).
374 struct call_if_statement<false, Then,
375     #ifndef BOOST_CONTRACT_DETAIL_DOXYGEN
376         boost::contract::detail::none
377     #else
378         internal_type
379     #endif
380 > {
381     /**
382     Construct this object with the then-branch functor template.
383
384     @param f    Then-branch nullary functor template.
385                 The functor template call @c f() is never compiled or executed
386                 for this template specialization (because the if-statement
387                 static predicate is @c false).
388                 The return type of @c f() must be the same as (or implicitly
389                 convertible to) the return type of all other functor template
390                 calls specified for this call-if object.
391     */
392     explicit call_if_statement(Then const&
393         #ifdef BOOST_CONTRACT_DETAIL_DOXYGEN
394             f
395         #endif
396     ) {}
397
398     // Do not provide `operator result_type()` here, require else_ instead.
399
400     /**
401     Specify the else-branch functor template.
402
403     @note   The <c>result_of<Else()>::type</c> expression needs be evaluated
404             only when the static predicate is already checked to be @c false
405             (because @c Else() is required to compile only in that case).
406             Thus, this result-of expression is evaluated lazily and only in
407             instantiations of this template specialization.
408     
409     @param f    Else-branch nullary functor template.
410                 The functor template call @c f() is actually compiled and
411                 executed for this template specialization (because the
412                 if-statement static predicate is @c false).
413                 The return type of @c f() must be the same as (or implicitly
414                 convertible to) the return type of all other functor template
415                 calls specified for this call-if object.
416     
417     @return A copy of the value returned by the call to the else-branch functor
418             template @c f().
419     */
420     template<typename Else>
421     #ifndef BOOST_CONTRACT_DETAIL_DOXYGEN
422         BOOST_CONTRACT_CALL_IF_RESULT_OF_(Else)
423     #else
424         typename result_of<Else()>::type
425     #endif
426     else_(Else f) const { return f(); }
427     
428     /**
429     Specify an else-if-branch functor template (using a static boolean
430     predicate).
431
432     @param f    Else-if-branch nullary functor template.
433                 The functor template call @c f() is actually compiled and
434                 executed if and only if @c ElseIfPred is @c true (because the
435                 if-statement static predicate is already @c false for this
436                 template specialization).
437                 The return type of @c f() must be the same as (or implicitly
438                 convertible to) the return type of all other functor template
439                 calls specified for this call-if object.
440     
441     @tparam ElseIfPred  Static boolean predicate selecting which functor
442                         template call to compile and execute.
443
444     @return A call-if statement so the else statement and additional else-if
445             statements can be specified if needed.
446             Eventually, this will be the return value of the one functor
447             template call being compiled and executed.
448     */
449     template<bool ElseIfPred, typename ElseIfThen>
450     call_if_statement<ElseIfPred, ElseIfThen> else_if_c(ElseIfThen f) const {
451         return call_if_statement<ElseIfPred, ElseIfThen>(f);
452     }
453     
454     /**
455     Specify an else-if-branch functor template (using a nullary boolen
456     meta-function).
457
458     @param f    Else-if-branch nullary functor template.
459                 The functor template call @c f() is actually compiled and
460                 executed if and only if @c ElseIfPred::value is @c true (because
461                 the if-statement static predicate is already @c false for this
462                 template specialization).
463                 The return type of @c f() must be the same as (or implicitly
464                 convertible to) the return type of all other functor template
465                 calls specified for this call-if object.
466
467     @tparam ElseIfPred  Nullary boolean meta-function selecting which functor
468                         template call to compile and execute.
469
470     @return A call-if statement so the else statement and additional else-if
471             statements can be specified if needed.
472             Eventually, this will be the return value of the one functor
473             template call being compiled and executed.
474     */
475     template<class ElseIfPred, typename ElseIfThen>
476     call_if_statement<ElseIfPred::value, ElseIfThen> else_if(ElseIfThen f)
477             const {
478         return call_if_statement<ElseIfPred::value, ElseIfThen>(f);
479     }
480 };
481
482 /**
483 Select compilation and execution of functor template calls using a static
484 boolean predicate (not needed on C++17 compilers, use <c>if constexpr</c>
485 instead).
486
487 Create a call-if object with the specified then-branch functor template:
488
489 @code
490 boost::contract::call_if_c<Pred1>(
491     then_functor_template1
492 ).template else_if_c<Pred2>(            // Optional.
493     then_functor_template2
494 )                                       // Optionally, other `else_if_c` or
495 ...                                     // `else_if`.
496 .else_(                                 // Optional for `void` functors,
497     else_functor_template               // but required for non `void`.
498 )
499 @endcode
500
501 Optional functor templates for else-if-branches and the else-branch can be
502 specified as needed (the else-branch function template is required if @c f
503 returns non-void).
504
505 @see    @RefSect{extras.assertion_requirements__templates_,
506         Assertion Requirements}
507
508 @param f    Then-branch nullary functor template.
509             The functor template call @c f() is compiled and executed if and
510             only if @c Pred is @c true.
511             The return type of other functor template calls specified for this
512             call-if statement (else-branch, else-if-branches, etc.) must be the
513             same as (or implicitly convertible to) the return type of
514             then-branch functor call @c f().
515
516 @tparam Pred    Static boolean predicate selecting which functor template call
517                 to compile and execute.
518
519 @return A call-if statement so else and else-if statements can be specified if
520         needed.
521         Eventually, this will be the return value of the one functor template
522         call being compiled and executed (which could also be @c void).
523 */
524 template<bool Pred, typename Then>
525 call_if_statement<Pred, Then> call_if_c(Then f) {
526     return call_if_statement<Pred, Then>(f);
527 }
528
529 /**
530 Select compilation and execution of functor template calls using a nullary
531 boolean meta-function (not needed on C++17 compilers, use <c>if constexpr</c>
532 instead).
533
534 This is equivalent to <c>boost::contract::call_if_c<Pred::value>(f)</c>.
535 Create a call-if object with the specified then-branch functor template:
536
537 @code
538 boost::contract::call_if<Pred1>(
539     then_functor_template1
540 ).template else_if<Pred2>(              // Optional.
541     then_functor_template2
542 )                                       // Optionally, other `else_if` or
543 ...                                     // `else_if_c`.
544 .else_(                                 // Optional for `void` functors,
545     else_functor_template               // but required for non `void`.
546 )
547 @endcode
548
549 Optional functor templates for else-if-branches and the else-branch can be
550 specified as needed (the else-branch functor template is required if @c f
551 returns non-void).
552
553 @see    @RefSect{extras.assertion_requirements__templates_,
554         Assertion Requirements}
555
556 @param f    Then-branch nullary functor template.
557             The functor template call @c f() is compiled and executed if and
558             only if @c Pred::value is @c true.
559             The return type of other functor template calls specified for this
560             call-if statement (else-branch, else-if-branches, etc.) must be the
561             same as (or implicitly convertible to) the return type of
562             then-branch functor template call @c f().
563
564 @tparam Pred    Nullary boolean meta-function selecting which functor template
565                 call to compile and execute.
566
567 @return A call-if statement so else and else-if statements can be specified if
568         needed.
569         Eventually, this will be the return value of the one functor template
570         call being compiled and executed (which could also be @c void).
571 */
572 template<class Pred, typename Then>
573 call_if_statement<Pred::value, Then> call_if(Then f) {
574     return call_if_statement<Pred::value, Then>(f);
575 }
576
577 /**
578 Select compilation and execution of a boolean functor template condition using a
579 static boolean predicate (not needed on C++17 compilers, use
580 <c>if constexpr</c> instead).
581
582 Compile and execute the nullary boolean functor template call @c f() if and only
583 if the specified static boolean predicate @p Pred is @c true, otherwise
584 trivially return @p else_ (@c true by default) at run-time.
585
586 A call to <c>boost::contract::condition_if_c<Pred>(f, else_)</c> is logically
587 equivalent to <c>boost::contract::call_if_c<Pred>(f, [] { return else_; })</c>
588 (but its internal implementation is optimized and it does not actually use
589 @c call_if_c).
590
591 @see    @RefSect{extras.assertion_requirements__templates_,
592         Assertion Requirements}
593
594 @param f    Nullary boolean functor template.
595             The functor template call @c f() is compiled and executed if and
596             only if @c Pred is @c true.
597
598 @tparam Pred    Static boolean predicate selecting when the functor template
599                 call @c f() should be compiled and executed.
600 @param else_    Boolean value to return when @c Pred is @c false (instead of
601                 compiling and executing the functor template call @c f()).
602
603 @return Boolean value returned by @c f() if the static predicate @c Pred is
604         @c true. Otherwise, trivially return @p else_.
605 */
606 #ifdef BOOST_CONTRACT_DETAIL_DOXYGEN
607     template<bool Pred, typename Then>
608     bool condition_if_c(Then f, bool else_ = true);
609 #else
610     // NOTE: condition_if is a very simple special case of call_if so it can be
611     // trivially implemented using enable_if instead of call_if as done below.
612
613     template<bool Pred, typename Then>
614     typename boost::enable_if_c<Pred, bool>::type
615     condition_if_c(Then f, bool /* else_ */ = true) { return f(); }
616
617     template<bool Pred, typename Then>
618     typename boost::disable_if_c<Pred, bool>::type
619     condition_if_c(Then /* f */, bool else_ = true) { return else_; }
620 #endif
621
622 /**
623 Select compilation and execution of a boolean functor template condition using a
624 nullary boolean meta-function (not needed on C++17 compilers, use
625 <c>if constexpr</c> instead).
626
627 This is equivalent to
628 <c>boost::contract::condition_if_c<Pred::value>(f, else_)</c>.
629 Compile and execute the nullary boolean functor template call @c f() if and only
630 if the specified nullary boolean meta-function @p Pred::value is @c true,
631 otherwise trivially return @p else_ (@c true by default) at run-time.
632
633 @see    @RefSect{extras.assertion_requirements__templates_,
634         Assertion Requirements}
635
636 @param f    Nullary boolean functor template.
637             The functor template call @c f() is compiled and executed if and
638             only if @c Pred::value is @c true.
639 @param else_    Boolean value to return when @c Pred::value is @c false (instead
640                 of compiling and executing the functor template call @c f()).
641
642 @tparam Pred    Nullary boolean meta-function selecting when the functor
643                 template call @c f() should be compiled and executed.
644
645 @return Boolean value returned by @c f() if the static predicate @c Pred::value
646         is @c true. Otherwise, trivially return @p else_.
647 */
648 template<class Pred, typename Then>
649 bool condition_if(Then f, bool else_ = true) {
650     return condition_if_c<Pred::value>(f, else_);
651 }
652
653 } } // namespace
654
655 #endif // #include guard
656