From 4fe7807f79a3cb2f4d3b93d167c3619c882552cf Mon Sep 17 00:00:00 2001 From: Edward Diener Date: Sun, 20 Oct 2019 17:00:51 -0400 Subject: [PATCH 1/7] Add BOOST_PP_VA_OPT implementation --- .../boost/preprocessor/facilities/va_opt.hpp | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 include/boost/preprocessor/facilities/va_opt.hpp diff --git a/include/boost/preprocessor/facilities/va_opt.hpp b/include/boost/preprocessor/facilities/va_opt.hpp new file mode 100644 index 0000000..bb25f1b --- /dev/null +++ b/include/boost/preprocessor/facilities/va_opt.hpp @@ -0,0 +1,29 @@ +# /* ************************************************************************** +# * * +# * (C) Copyright Edward Diener 2019. +# * Distributed under the Boost Software License, Version 1.0. (See +# * accompanying file LICENSE_1_0.txt or copy at +# * http://www.boost.org/LICENSE_1_0.txt) +# * * +# ************************************************************************** */ +# +# /* See http://www.boost.org for most recent version. */ +# +# ifndef BOOST_PREPROCESSOR_FACILITIES_VA_OPT_HPP +# define BOOST_PREPROCESSOR_FACILITIES_VA_OPT_HPP +# include +# if BOOST_PP_VARIADIC_HAS_OPT() +# include +# include +# include +# define BOOST_PP_VA_OPT(rdata,rempty,...) \ + BOOST_PP_TUPLE_REM() \ + BOOST_PP_IIF \ + ( \ + BOOST_PP_CHECK_EMPTY(__VA_ARGS__), \ + rempty, \ + rdata \ + } \ +/**? +# endif /* BOOST_PP_VARIADIC_HAS_OPT() */ +# endif /* BOOST_PREPROCESSOR_FACILITIES_VA_OPT_HPP */ From a9827c8fc8bf611dfdc771f4349637534740227a Mon Sep 17 00:00:00 2001 From: Edward Diener Date: Wed, 30 Oct 2019 14:32:45 -0400 Subject: [PATCH 2/7] Updated docs __VA_OPT__ support. --- doc/headers/facilities.html | 1 + doc/topics/emptiness.html | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/doc/headers/facilities.html b/doc/headers/facilities.html index 90eaa39..c8c45b5 100644 --- a/doc/headers/facilities.html +++ b/doc/headers/facilities.html @@ -15,6 +15,7 @@
  • <boost/preprocessor/facilities/apply.hpp>
  • <boost/preprocessor/facilities/empty.hpp>
  • +
  • <boost/preprocessor/facilities/check_empty.hpp>
  • <boost/preprocessor/facilities/expand.hpp>
  • <boost/preprocessor/facilities/identity.hpp>
  • <boost/preprocessor/facilities/intercept.hpp>
  • diff --git a/doc/topics/emptiness.html b/doc/topics/emptiness.html index 04008dc..b86c7c1 100644 --- a/doc/topics/emptiness.html +++ b/doc/topics/emptiness.html @@ -32,11 +32,11 @@

    Expanding to nothing

    Given certain arguments a macro might expand to nothing, aka no preprocessor tokens. This may - happen more than the previous case of an argument to a macro being nothing because the expansion of a macro + happen more than in the previous case of an argument to a macro being nothing because the expansion of a macro is often used to initialize some C++ construct, and C++ has some places where a part of a compile-time construct can be empty. However a macro which expands to nothing - rarely occurs when a macro's expansion is used as an argument to another macro, although - again it is perfectly legal C++. + rarely occurs when that macro's expansion is used as an argument to another macro because we would again have + a macro where we are passing nothing as an argument.
    
    From 776037ae56fb3aa91435b307eb14feccb15e7271 Mon Sep 17 00:00:00 2001
    From: Edward Diener 
    Date: Thu, 31 Oct 2019 06:07:10 -0400
    Subject: [PATCH 3/7] Corrected implementation and testing for BOOST_PP_VA_OPT
    
    ---
     .../boost/preprocessor/facilities/va_opt.hpp  | 23 +++--
     test/Jamfile.v2                               |  1 +
     test/vaopt.cpp                                | 12 +++
     test/vaopt.cxx                                | 88 +++++++++++++++++++
     4 files changed, 115 insertions(+), 9 deletions(-)
     create mode 100644 test/vaopt.cpp
     create mode 100644 test/vaopt.cxx
    
    diff --git a/include/boost/preprocessor/facilities/va_opt.hpp b/include/boost/preprocessor/facilities/va_opt.hpp
    index bb25f1b..de0e69e 100644
    --- a/include/boost/preprocessor/facilities/va_opt.hpp
    +++ b/include/boost/preprocessor/facilities/va_opt.hpp
    @@ -16,14 +16,19 @@
     # include 
     # include 
     # include 
    -# define BOOST_PP_VA_OPT(rdata,rempty,...) \
    -    BOOST_PP_TUPLE_REM() \
    -    BOOST_PP_IIF \
    -        ( \
    -        BOOST_PP_CHECK_EMPTY(__VA_ARGS__), \
    -        rempty, \
    -        rdata \
    -        } \
    -/**?
    +# define BOOST_PP_VA_OPT_IMPL(atuple) \
    +    BOOST_PP_TUPLE_REM() atuple       \
    +/**/
    +# define BOOST_PP_VA_OPT(rdata,rempty,...)     \
    +    BOOST_PP_VA_OPT_IMPL                       \
    +        (                                      \
    +        BOOST_PP_IIF                           \
    +            (                                  \
    +            BOOST_PP_CHECK_EMPTY(__VA_ARGS__), \
    +            rempty,                            \
    +            rdata                              \
    +            )                                  \
    +        )                                      \
    +/**/
     # endif /* BOOST_PP_VARIADIC_HAS_OPT() */
     # endif /* BOOST_PREPROCESSOR_FACILITIES_VA_OPT_HPP */
    diff --git a/test/Jamfile.v2 b/test/Jamfile.v2
    index 811e4e2..fbda6c0 100644
    --- a/test/Jamfile.v2
    +++ b/test/Jamfile.v2
    @@ -214,6 +214,7 @@ alias preprocessor_isempty
            [ compile checkempty.cpp ]
            [ compile-fail isempty_variadic_standard_failure.cpp : BOOST_PP_VARIADICS=1 ]
            [ compile-fail isempty_variadic_standard_failure2.cpp : BOOST_PP_VARIADICS=1 ]
    +       [ compile vaopt.cpp ]
      ; 
       
     alias preprocessor_isempty_nvm
    diff --git a/test/vaopt.cpp b/test/vaopt.cpp
    new file mode 100644
    index 0000000..9801a19
    --- /dev/null
    +++ b/test/vaopt.cpp
    @@ -0,0 +1,12 @@
    +# /* **************************************************************************
    +#  *                                                                          *
    +#  *     (C) Copyright Edward Diener 2019.
    +#  *     Distributed under the Boost Software License, Version 1.0. (See
    +#  *     accompanying file LICENSE_1_0.txt or copy at
    +#  *     http://www.boost.org/LICENSE_1_0.txt)
    +#  *                                                                          *
    +#  ************************************************************************** */
    +#
    +# /* See http://www.boost.org for most recent version. */
    +#
    +# include 
    diff --git a/test/vaopt.cxx b/test/vaopt.cxx
    new file mode 100644
    index 0000000..6cb8702
    --- /dev/null
    +++ b/test/vaopt.cxx
    @@ -0,0 +1,88 @@
    +# /* **************************************************************************
    +#  *                                                                          *
    +#  *     (C) Copyright Edward Diener 2019.
    +#  *     Distributed under the Boost Software License, Version 1.0. (See
    +#  *     accompanying file LICENSE_1_0.txt or copy at
    +#  *     http://www.boost.org/LICENSE_1_0.txt)
    +#  *                                                                          *
    +#  ************************************************************************** */
    +#
    +# /* See http://www.boost.org for most recent version. */
    +#
    +# include 
    +# include 
    +
    +# if BOOST_PP_VARIADIC_HAS_OPT()
    +
    +# include 
    +# include 
    +# include 
    +
    +#define DATA
    +#define OBJECT OBJECT2
    +#define OBJECT2
    +#define FUNC(x) FUNC2(x)
    +#define FUNC2(x)
    +#define FUNC_GEN() ()
    +#define FUNC_GEN2(x) ()
    +#define FUNC_GEN3() (&)
    +#define FUNC_GEN4(x) (y)
    +#define FUNC_GEN5() (y,z)
    +#define FUNC_GEN6() anything
    +#define FUNC_GEN7(x) anything
    +#define FUNC_GEN8(x,y) (1,2,3)
    +#define FUNC_GEN9(x,y,z) anything
    +#define FUNC_GEN10(x) (y) data
    +#define NAME &name
    +#define ATUPLE (atuple)
    +#define ATUPLE_PLUS (atuple) data
    +
    +#define TRY_PASS_EMPTY_STD(...) BOOST_PP_VARIADIC_ELEM(0, __VA_OPT__ (0,) 1)
    +#define TRY_PASS_EMPTY_BOOST(...) BOOST_PP_VARIADIC_ELEM(0,BOOST_PP_VA_OPT((0),(1),__VA_ARGS__))
    +
    +BEGIN TRY_PASS_EMPTY_STD(FUNC_GEN) == 0 END
    +BEGIN TRY_PASS_EMPTY_BOOST(FUNC_GEN) == 0 END
    +BEGIN TRY_PASS_EMPTY_STD(FUNC_GEN2) == 0 END
    +BEGIN TRY_PASS_EMPTY_BOOST(FUNC_GEN2) == 0 END
    +BEGIN TRY_PASS_EMPTY_STD(FUNC_GEN3) == 0 END
    +BEGIN TRY_PASS_EMPTY_BOOST(FUNC_GEN3) == 0 END
    +BEGIN TRY_PASS_EMPTY_STD(FUNC_GEN4) == 0 END
    +BEGIN TRY_PASS_EMPTY_BOOST(FUNC_GEN4) == 0 END
    +BEGIN TRY_PASS_EMPTY_STD(FUNC_GEN5) == 0 END
    +BEGIN TRY_PASS_EMPTY_BOOST(FUNC_GEN5) == 0 END
    +BEGIN TRY_PASS_EMPTY_STD(FUNC_GEN8) == 0 END
    +BEGIN TRY_PASS_EMPTY_BOOST(FUNC_GEN8) == 0 END
    +BEGIN TRY_PASS_EMPTY_STD(FUNC_GEN9) == 0 END
    +BEGIN TRY_PASS_EMPTY_BOOST(FUNC_GEN9) == 0 END
    +BEGIN TRY_PASS_EMPTY_STD(FUNC_GEN10) == 0 END
    +BEGIN TRY_PASS_EMPTY_BOOST(FUNC_GEN10) == 0 END
    +BEGIN TRY_PASS_EMPTY_STD(BOOST_PP_EMPTY()) == 1 END
    +BEGIN TRY_PASS_EMPTY_BOOST(BOOST_PP_EMPTY()) == 1 END
    +BEGIN TRY_PASS_EMPTY_STD(DATA BOOST_PP_EMPTY()) == 1 END
    +BEGIN TRY_PASS_EMPTY_BOOST(DATA BOOST_PP_EMPTY()) == 1 END
    +BEGIN TRY_PASS_EMPTY_STD() == 1 END
    +BEGIN TRY_PASS_EMPTY_BOOST() == 1 END
    +BEGIN TRY_PASS_EMPTY_STD(DATA) == 1 END
    +BEGIN TRY_PASS_EMPTY_BOOST(DATA) == 1 END
    +BEGIN TRY_PASS_EMPTY_STD(x BOOST_PP_EMPTY()) == 0 END
    +BEGIN TRY_PASS_EMPTY_BOOST(x BOOST_PP_EMPTY()) == 0 END
    +BEGIN TRY_PASS_EMPTY_STD(OBJECT BOOST_PP_EMPTY()) == 1 END
    +BEGIN TRY_PASS_EMPTY_BOOST(OBJECT BOOST_PP_EMPTY()) == 1 END
    +BEGIN TRY_PASS_EMPTY_STD(FUNC(z) BOOST_PP_EMPTY()) == 1 END
    +BEGIN TRY_PASS_EMPTY_BOOST(FUNC(z) BOOST_PP_EMPTY()) == 1 END
    +BEGIN TRY_PASS_EMPTY_STD(FUNC_GEN6) == 0 END
    +BEGIN TRY_PASS_EMPTY_BOOST(FUNC_GEN6) == 0 END
    +BEGIN TRY_PASS_EMPTY_STD(FUNC_GEN7) == 0 END
    +BEGIN TRY_PASS_EMPTY_BOOST(FUNC_GEN7) == 0 END
    +BEGIN TRY_PASS_EMPTY_STD(NAME) == 0 END
    +BEGIN TRY_PASS_EMPTY_BOOST(NAME) == 0 END
    +BEGIN TRY_PASS_EMPTY_STD(ATUPLE) == 0 END
    +BEGIN TRY_PASS_EMPTY_BOOST(ATUPLE) == 0 END
    +BEGIN TRY_PASS_EMPTY_STD(ATUPLE_PLUS) == 0 END
    +BEGIN TRY_PASS_EMPTY_BOOST(ATUPLE_PLUS) == 0 END
    +
    +# else
    +
    +BEGIN 1 == 1 END
    +
    +# endif
    
    From c5e90f23b7ebc0ec1eec7f10d6db9712cf00ab4c Mon Sep 17 00:00:00 2001
    From: Edward Diener 
    Date: Fri, 1 Nov 2019 15:34:08 -0400
    Subject: [PATCH 4/7] Updated check_empty variadic macro notation.
    
    ---
     doc/headers.html                        | 3 ++-
     doc/headers/facilities.html             | 2 +-
     doc/headers/facilities/check_empty.html | 2 +-
     doc/ref.html                            | 2 +-
     4 files changed, 5 insertions(+), 4 deletions(-)
    
    diff --git a/doc/headers.html b/doc/headers.html
    index 7728e18..651de5b 100644
    --- a/doc/headers.html
    +++ b/doc/headers.html
    @@ -80,7 +80,8 @@
           
  • facilities.hpp
  • facilities/
  • apply.hpp
  • -
  • check_empty.hpp
  • +
  • check_empty.hpp + (v)
  • empty.hpp
  • expand.hpp
  • identity.hpp
  • diff --git a/doc/headers/facilities.html b/doc/headers/facilities.html index c8c45b5..b4166f9 100644 --- a/doc/headers/facilities.html +++ b/doc/headers/facilities.html @@ -15,7 +15,7 @@

    Contents


    diff --git a/doc/ref.html b/doc/ref.html index f518c42..a627296 100644 --- a/doc/ref.html +++ b/doc/ref.html @@ -45,7 +45,7 @@
  • BOOL
  • CAT
  • -
  • CHECK_EMPTY
  • +
  • CHECK_EMPTY (v)
  • COMMA
  • COMMA_IF
  • COMPL
  • From 4f4f04c56b97265511a22b2e2a2fe096f238ff5d Mon Sep 17 00:00:00 2001 From: Edward Diener Date: Fri, 1 Nov 2019 15:51:34 -0400 Subject: [PATCH 5/7] Added va_opt.hpp to facilities header file. --- include/boost/preprocessor/facilities.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/include/boost/preprocessor/facilities.hpp b/include/boost/preprocessor/facilities.hpp index 291b78e..fba37b5 100644 --- a/include/boost/preprocessor/facilities.hpp +++ b/include/boost/preprocessor/facilities.hpp @@ -20,5 +20,6 @@ # include # include # include +# include # # endif From de4967645230f7e174575aa31738e4abf4593d50 Mon Sep 17 00:00:00 2001 From: Edward Diener Date: Sat, 2 Nov 2019 18:59:55 -0400 Subject: [PATCH 6/7] Added docs for the BOOST_PP_VA_OPT macro. --- doc/headers.html | 2 + doc/headers/facilities/va_opt.html | 32 ++++++++ doc/ref.html | 1 + doc/ref/va_opt.html | 124 +++++++++++++++++++++++++++++ 4 files changed, 159 insertions(+) create mode 100644 doc/headers/facilities/va_opt.html create mode 100644 doc/ref/va_opt.html diff --git a/doc/headers.html b/doc/headers.html index 651de5b..543667e 100644 --- a/doc/headers.html +++ b/doc/headers.html @@ -88,6 +88,8 @@
  • intercept.hpp
  • overload.hpp (v)
  • +
  • va_opt.hpp + (v)
  • for.hpp*
  • identity.hpp*
  • if.hpp*
  • diff --git a/doc/headers/facilities/va_opt.html b/doc/headers/facilities/va_opt.html new file mode 100644 index 0000000..5e6c8fa --- /dev/null +++ b/doc/headers/facilities/va_opt.html @@ -0,0 +1,32 @@ + + + + + facilities/va_opt.hpp + + + +
    The facilities/va_opt.hpp + header defines a variadic macro for the C++20 level that offers a + more flexible alternative to the __VA_OPT__ construct.
    +

    Usage

    +
    #include <boost/preprocessor/facilities/va_opt.hpp> +
    +

    Contents

    + +
    +
    © Copyright Edward Diener 2019 +
    +
    +

    Distributed under the Boost Software License, Version + 1.0. (See accompanying file LICENSE_1_0.txt or + copy at www.boost.org/LICENSE_1_0.txt)

    +
    + + diff --git a/doc/ref.html b/doc/ref.html index a627296..f5328e6 100644 --- a/doc/ref.html +++ b/doc/ref.html @@ -296,6 +296,7 @@
  • UPDATE_COUNTER
  • +
  • VA_OPT (v)
  • VALUE
  • VARIADICS
  • VARIADIC_ELEM (v)
  • diff --git a/doc/ref/va_opt.html b/doc/ref/va_opt.html new file mode 100644 index 0000000..694ba27 --- /dev/null +++ b/doc/ref/va_opt.html @@ -0,0 +1,124 @@ + + + + + BOOST_PP_VA_OPT + + + +
    The BOOST_PP_VA_OPT variadic + macro is a more flexible alternative to the C++20 __VA_OPT__ + construct. It expands to either one of two inputs depending on + whether the variadic data is empty or not, whereas the C++20 + __VA_OPT__ constructs expands to either its input or nothing + depending on whether the variadic data is empty or not. This macro + only exists when the compilation is at the C++20 level and the + __VA_OPT__ construct is supported.
    +

    Usage

    +
    BOOST_PP_VA_OPT(x,y,...) (v)
    +
    +

    Arguments

    +

          x
    +           A tuple + whose data is the macro expansion if the variadic data is + not empty
    +       y
    +           A tuple + whose data is the macro expansion if the variadic data is + empty
    +       ,,,
    +           The variadic + data to be checked for emptiness
    +

    +
    +
    +

    Remarks

    +
    When the macro invocation BOOST_PP_VARIADIC_HAS_OPT() expands + to 1, then this macro exists and can be invoked, otherwise this + macro does not exist and attempting to invoke it will lead to a + preprocessor error that the macro can not be found. Because of + this condition the header file for including this macro includes + the header file for the BOOST_PP_VARIADIC_HAS_OPT macro.
    +
    + The difference between this macro and the __VA_OPT__ construct + illustrates a limitation of the latter construct with a trade off + of simpler syntax. The differences between the __VA_OPT__ + construct and this macro are:
    +
      +
    • The __VA_OPT__ construct offers a choice as its expansion + only between its input preprocessing tokens or nothing ( + called a "single placemarker token" ) depending on whether the + implicit variadic data is empty or not. There is no way using + the __VA_OPT__ construct to specify any alternative but the + "single placemarker token" when the variadic data is empty + whereas any preprocessing tokens can be specified when the + variadic data is not empty. With the BOOST_PP_VA_OPT macro the + user can specify as its expansion preprocessing tokens both + when the variadic data is empty and when the variadic data is + not empty.
    • +
    • The __VA_OPT__ construct offers a simple syntax whereas this + macro is more verbose. The BOOST_PP_VA_OPT macro's first and + second parameters must be Boost PP tuples of data, in order to + expand to normal or variadic data, and the third parameter + must be the variadic data to check for emptiness, whereas the + __VA_OPT__ construct has an implied variadic data as + __VA_ARGS__ to check for emptiness and can specify its + expansion directly in terms of its input.
    • +
    • The __VA_OPT__ construct can only be specified in the + replacement list of some macro, whereas the BOOST_PP_VA_OPT + macro can be used both as an alternative to the __VA_OPT__ + construct in the replacement list of some macro and anywhere + else a macro can be used.
    • +
    • It is impossible to have a left parenthesis '(' or a right + parenthesis ')' as preprocessing token data within the + __VA_OPT__ construct whereas both are possible as part of the + expanded data for the BOOST_PP_VA_OPT macro.
      +
    • +
    +
    + The exact BOOST_PP_VA_OPT equivalent to the construct of  + '__VA_OPT__ ( pp-tokens )' in the replacement list of a macro is + 'BOOST_PP_VA_OPT (( pp-tokens ),(),__VA_ARGS__)'.
    +

    See Also

    + +

    Requirements

    + +

    Sample Code

    +
    +
    #include <boost/preprocessor/facilities/va_opt.hpp>
    +
    +# if BOOST_PP_VARIADIC_HAS_OPT()
    +
    +#define DATA
    +#define OBJECT OBJECT2
    +#define OBJECT2
    +#define FUNC(x) FUNC2(x)
    +#define FUNC2(x)
    +#define FUNC_GEN(x,y) (1,2,3)
    +
    +BOOST_PP_VA_OPT((1),(2),DATA)                      // expands to 2
    +BOOST_PP_VA_OPT((3),(4),OBJECT)                    // expands to 4
    +BOOST_PP_VA_OPT((5),(6),FUNC(1))                   // expands to 6
    +BOOST_PP_VA_OPT((7,8),(9,10),FUNC)                 // expands to 7,8
    +BOOST_PP_VA_OPT((1,2,3,4,5),(6,7,8,9,10),FUNC_GEN) // expands to 1,2,3,4,5
    +
    +#endif
    +
    +
    +
    +
    © Copyright Edward Diener 2019 +
    +
    +

    Distributed under the Boost Software License, Version + 1.0. (See accompanying file LICENSE_1_0.txt or + copy at www.boost.org/LICENSE_1_0.txt)

    +
    + + From b3036f1a6379bf2c76baf5e9d9b6992c43f60f19 Mon Sep 17 00:00:00 2001 From: Edward Diener Date: Sat, 2 Nov 2019 23:58:29 -0400 Subject: [PATCH 7/7] Expanded emptiness explanation with the addition of the BOOST_PP_VA_OPT macro. --- doc/topics/emptiness.html | 287 +++++++++++++++++++++++--------------- 1 file changed, 173 insertions(+), 114 deletions(-) diff --git a/doc/topics/emptiness.html b/doc/topics/emptiness.html index b86c7c1..ce346c8 100644 --- a/doc/topics/emptiness.html +++ b/doc/topics/emptiness.html @@ -1,21 +1,22 @@ + - + emptiness.html - +

    Passing nothing

    -
    - Although rarely desirable it has always been legal in C++ to pass nothing, aka no preprocessor tokens, - as an argument when invoking a macro, whether the equivalent parameter be a regular parameter or a variadic one. -
    -
    -
    -      #define SOME_MACRO(Parameter1,Parameter2) macro expansion using Parameter1 and Parameter2
    +    
    Although rarely desirable it has always been legal in C++ to + pass nothing, aka no preprocessor tokens, as an argument when + invoking a macro, whether the equivalent parameter be a regular + parameter or a variadic one.
    +
    +
          #define SOME_MACRO(Parameter1,Parameter2) macro expansion using Parameter1 and Parameter2
           #define SOME_VARIADIC_MACRO(Parameter1,...) macro expansion using Parameter1 and __VA_ARGS__
           
           SOME_MACRO(a,b) // Normal
    @@ -30,17 +31,17 @@
                                           but in C++20 exactly equivalent to SOME_VARIADIC_MACRO(a,) */

    Expanding to nothing

    -
    - Given certain arguments a macro might expand to nothing, aka no preprocessor tokens. This may - happen more than in the previous case of an argument to a macro being nothing because the expansion of a macro - is often used to initialize some C++ construct, and C++ has some places where - a part of a compile-time construct can be empty. However a macro which expands to nothing - rarely occurs when that macro's expansion is used as an argument to another macro because we would again have - a macro where we are passing nothing as an argument. -
    -
    -
    -      #define ANOTHER_MACRO(Parameter1,Parameter2) /* expands to nothing when Parameter1 and Parameter2
    +    
    Given certain arguments a macro might expand to nothing, aka + no preprocessor tokens. This may happen more than in the previous + case of an argument to a macro being nothing because the expansion + of a macro is often used to initialize some C++ construct, and C++ + has some places where a part of a compile-time construct can be + empty. However a macro which expands to nothing rarely occurs when + that macro's expansion is used as an argument to another macro + because we would again have a macro where we are passing nothing + as an argument.
    +
    +
          #define ANOTHER_MACRO(Parameter1,Parameter2) /* expands to nothing when Parameter1 and Parameter2
                                                           are numbers, otherwise expands to some preprocessing
                                                           token, such as '1' */
           
    @@ -50,103 +51,161 @@
           SOME_MACRO(ANOTHER_MACRO(1,2),z)          // Legal, first argument is empty as ANOTHER_MACRO Expands to nothing

    Emptiness defined

    -
    - Passing nothing as a macro argument or a macro expanding to nothing I term as 'emptiness', - as 'nothing' is too amorphous a term which can be used in too many other contexts for my liking. - In the vast majority of cases when designing a macro for use emptiness is not a part of such - a design, and passing emptiness as an argument or expanding to emptiness is not anything - that someone writing a macro takes into account when he explains to other programmers - how a macro should be used.

    - Other than the fact that macros are generally created so that some actual preprocessor - data of a particular kind needs to be passed as arguments or gets generated as part of - macro expansion when a macro is invoked, there is another very good reason why working - with emptiness is not part of a macro's design: there has been no perfectly fail-safe - way to test for emptiness during macro expansion, whether it be in creating macros - using just the facilities of the C++ standard or using a 3rd party library, such as - this Boost preprocessor library. When I say 'fail-safe' I mean that there has always - been some argument input, no matter how small the number of potential cases, where a - macro designed to test whether or not the preprocessor data passed to it as an argument - when the macro is invoked is actually empty, fails in some - way, with the failure normally occurring as a preprocessor error.

    - Of course this does not mean that the best macro designed to test for emptiness - will not work correctly the vast majority of the time. It only means that there - has been no guarantee that such a macro will work correctly all 100% of the time. - Nonetheless there have been uses of testing for emptiness, when a macro documents - what a particular argument should generally consist of, even if the test is not - guaranteed to work 100% of the time if particular unexpected argument data does get passed. -
    +
    Passing nothing as a macro argument or a macro expanding to + nothing I term as 'emptiness', as 'nothing' is too amorphous a + term which can be used in too many other contexts for my liking. + In the vast majority of cases when designing a macro for use + emptiness is not a part of such a design, and passing emptiness as + an argument or expanding to emptiness is not anything that someone + writing a macro takes into account when he explains to other + programmers how a macro should be used.
    +
    + Other than the fact that macros are generally created so that some + actual preprocessor data of a particular kind needs to be passed + as arguments or gets generated as part of macro expansion when a + macro is invoked, there is another very good reason why working + with emptiness is not part of a macro's design: there has been no + perfectly fail-safe way to test for emptiness during macro + expansion, whether it be in creating macros using just the + facilities of the C++ standard or using a 3rd party library, such + as this Boost preprocessor library. When I say 'fail-safe' I mean + that there has always been some argument input, no matter how + small the number of potential cases, where a macro designed to + test whether or not the preprocessor data passed to it as an + argument when the macro is invoked is actually empty fails in some + way, with the failure normally occurring as a preprocessor error.
    +
    + Of course this does not mean that the best macro designed to test + for emptiness will not work correctly the vast majority of the + time. It only means that there has been no guarantee that such a + macro will work correctly all 100% of the time. Nonetheless there + have been uses of testing for emptiness, when a macro documents + what a particular argument should generally consist of, even if + the test is not guaranteed to work 100% of the time if particular + unexpected argument data does get passed.

    A C++20 solution for testing for emptiness

    -
    - The C++ standard committee recognized, in the upcoming specification for the C++20 standard, - that a way of testing whether variadic data is empty or not in the expansion of a variadic - macro would be very useful when designing certain types of macros. Because of this - the C++20 standard added a preprocessor construct which could do this in a certain way - for variadic data in the expansion of a variadic macro. - The construct is called __VA_OPT__. I am not going to explain that construct here, as the - documentation for it is part of the upcoming C++20 standard and is readily available on - various C++ sites on the Internet, but the further upshot of adding the __VA_OPT__ construct - to C++20 is that it is now possible to create a variadic macro which is 100% reliable in - testing for emptiness whenever a compiler supports the __VA_OPT__ construct in its - compilation of preprocessor code.

    - For such a macro to always work which tests for emptiness the code must know when - the __VA_OPT__ construct is available. It is not enough to know that a compiler is - working at the C++20 level, since as all C++ programmers know an adherence to a C++ standard - level never guarantees that a particular compiler supports every aspect of that level. - Happily there is a way to test whether a compiler supports the __VA_OPT__ construct - as long as the compiler supports variadic macros, and that way has been openly published - on the Internet although the actual macro code would not have been hard to create even if it had - not publicly appeared. This library uses that code to test for __VA_OPT__ as a necessary prelude - for creating a variadic macro which is 100% reliable in testing for emptiness.

    - The Boost Preprocessor macro for testing whether the __VA_OPT__ construct is supported during - compilation is called BOOST_PP_VARIADIC_HAS_OPT, which is a function-like macro taking no parameters - and returning 1 if the __VA_OPT__ construct is supported and 0 if it is not. The macro - only returns 1 when variadic macros are supported, when the compiler is at the C++20 level, - and when the __VA_OPT__ construct can be used according to the C++20 standard. In particular - the macro needs the compiler to be working at the C++20 level despite the fact that at least - one major compiler supports the __VA_OPT__ construct in some of its latest releases even - when the compiler is being used at a C++ standard level below that of C++20. The reason this - Boost preprocessor library requires the C++20 level is because that same major compiler - can produce a warning, or even an error, when it even sees a macro using the __VA_OPT__ - construct at a level below C++20, even though it supports it, if other compiler options - requiring strict adherence to the level of the C++ standard being used are passed on the - command line. So taking a conservative approach the BOOST_PP_VARIADIC_HAS_OPT macros requires - compilation at the C++20 level, along with variadic macro support, along with the testing code - expanding to 1, in order to specify that __VA_OPT__ is supported.

    - The actual Boost Preprocessor library for testing for emptiness in C++20 mode is called - BOOST_PP_CHECK_EMPTY. The macro is a variadic macro with a single variadic parameter. The - macro only exists if our previous macro for testing for __VA_OPT__ called BOOST_PP_VARIADIC_HAS_OPT - expands to 1 when invoked as BOOST_PP_VARIADIC_HAS_OPT(). If BOOST_PP_VARIADIC_HAS_OPT() expands to 0 - the BOOST_PP_CHECK_EMPTY macro does not exist at all in this library. The input to the macro - can be any variadic data. If the data passed to the macro is empty, or if the data passed to - the macro is not empty but when the data itself is expanded it is empty, the macro returns - 1, otherwise it returns 0. The macro works 100% of the time and is completely reliable no matter what - preprocessor data is passed to it. But of course it only works when compiling at the C++20 - level with the __VA_OPT__ construct supported by the compiler. It solves an old problem - that it has never been possible, prior to C++20, to provide a 100% reliable implementation - of a macro which tests for emptiness in C++.

    - Eventually more C++ compilers will support C++20 and the __VA_OPT__ construct and more programmers - will use compilers at the C++20 level. At that point the macro BOOST_PP_CHECK_EMPTY can be - used reliably for testing emptiness in preprocessor data in macro code by all those programmers. - This does not mean that designing macros with emptiness in mind needs to be done, much less - considered, but that the possibility of doing so with complete reliability will be there if needed - by the macro programmer. Along with the __VA_OPT__ construct as mandated by the C++20 standard - the BOOST_PP_CHECK_EMPTY adds two more tools in the arsenal of macro programming, which is a good - thing, while programmers who wanted to ignore any dealing with emptiness in macro code can continue to do so. -
    +
    The C++ standard committee recognized, in the upcoming + specification for the C++20 standard, that a way of testing + whether variadic data is empty or not in the expansion of a + variadic macro would be very useful when designing certain types + of macros. Because of this the C++20 standard added a preprocessor + construct which could do this in a certain way for variadic data + in the expansion of a variadic macro. The construct is called + __VA_OPT__, as in '__VA_OPT__ ( prepocessing tokens )' specified + in the replacement list of a variadic macro.
    +
    + The way that the __VA_OPT__ constructs works is that if the + variadic arguments to the variadic macro are empty or expand to + emptiness then the __VA_OPT__ construct and its enclosed + preprocessing token data expands to nothing, or in C++ terms "a + single placemarker preprocessing token". Otherwise the __VA_OPT__ + construct expands to its enclosed preprocessing tokens. A further, + possibly unintended, upshot of adding the __VA_OPT__ construct to + C++20 is that it is now possible to create a variadic macro which + is 100% reliable in testing for emptiness whenever a compiler + supports the __VA_OPT__ construct in its compilation of + preprocessor code.
    +
    + For such a macro to always work which tests for emptiness the code + must know when the __VA_OPT__ construct is available. It is not + enough to know that a compiler is working at the C++20 level, + since as all C++ programmers know an adherence to a C++ standard + level never guarantees that a particular compiler supports every + aspect of that level. Happily there is a way to test whether a + compiler supports the __VA_OPT__ construct as long as the compiler + supports variadic macros, and that way has been openly published + on the Internet, although the actual macro code would not have + been hard to create even if it had not publicly appeared. This + library uses that code to test for __VA_OPT__ as a necessary + prelude for creating a variadic macro which is 100% reliable in + testing for emptiness.
    +
    + The Boost Preprocessor macro for testing whether the __VA_OPT__ + construct is supported during compilation is called + BOOST_PP_VARIADIC_HAS_OPT, which is a function-like macro taking + no parameters and returning 1 if the __VA_OPT__ construct is + supported and 0 if it is not. The macro only returns 1 when + variadic macros are supported, when the compiler is at the C++20 + level, and when the __VA_OPT__ construct can be used according to + the C++20 standard. In particular the macro needs the compiler to + be working at the C++20 level despite the fact that at least one + major compiler supports the __VA_OPT__ construct in some of its + latest releases even when the compiler is being used at a C++ + standard level below that of C++20. The reason this Boost + preprocessor library requires the C++20 level is because that same + major compiler can produce a warning, or even an error, when it + even sees a macro using the __VA_OPT__ construct at a level below + C++20, even though it supports it, if other compiler options + requiring strict adherence to the level of the C++ standard being + used are passed on the command line. So taking a conservative + approach the BOOST_PP_VARIADIC_HAS_OPT macros requires compilation + at the C++20 level, along with variadic macro support, along with + the testing code expanding to 1, in order to specify that + __VA_OPT__ is supported.
    +
    + The actual Boost Preprocessor library for testing for emptiness in + C++20 mode is called BOOST_PP_CHECK_EMPTY. The macro is a variadic + macro with a single variadic parameter. The macro only exists if + our previous macro for testing for __VA_OPT__, called + BOOST_PP_VARIADIC_HAS_OPT, expands to 1 when invoked as + BOOST_PP_VARIADIC_HAS_OPT(). If BOOST_PP_VARIADIC_HAS_OPT() + expands to 0 the BOOST_PP_CHECK_EMPTY macro does not exist at all + in this library. The input to the BOOST_PP_CHECK_EMPTY macro can + be any variadic data. If the data passed to the macro is empty, or + if the data passed to the macro is not empty but when the data + itself is expanded it is empty, the macro returns 1, otherwise it + returns 0. The macro works 100% of the time and is completely + reliable no matter what preprocessor data is passed to it. But of + course it only works when compiling at the C++20 level with the + __VA_OPT__ construct supported by the compiler. It solves an old + problem that it has never been possible, prior to C++20, to + provide a 100% reliable implementation of a macro which tests for + emptiness in C++.
    +
    + Along with the valuable BOOST_PP_CHECK_EMPTY macro the Boost + Preprocessor library has also added a more flexible, if slightly + verbose, alternative to the __VA_OPT__ construct, which works by + using the ability of BOOST_PP_CHECK_EMPTY to reliably test for + emptiness. This macro is called BOOST_PP_VA_OPT and allows the + programmer to specify preprocessing tokens for expansion both when + the variadic data is not empty and when the variadic data + is empty. This improves on the __VA_OPT__ construct's ability to + specify preprocessing tokens for expansion only when the variadic + data is not empty. Like BOOST_PP_CHECK_EMPTY, which it uses, the + BOOST_PP_VA_OPT macro only exists when BOOST_PP_VARIADIC_HAS_OPT() + expands to 1. You can read further about how this macro works as + an alternative to the C++20 __VA_OPT__ construct in the + documentation for the macro itself.
    +
    + Eventually more C++ compilers will support C++20 and the + __VA_OPT__ construct and more programmers will use compilers at + the C++20 level. At that point the macro BOOST_PP_CHECK_EMPTY can + be used reliably for testing emptiness in preprocessor data in + macro code by all those programmers. The BOOST_PP_VA_OPT macro + serves as a useful example of such use. This does not mean that + designing macros with emptiness in mind needs to be done, much + less considered, but that the possibility of doing so with + complete reliability will be there if needed by the macro + programmer. Along with the __VA_OPT__ construct as mandated by the + C++20 standard the BOOST_PP_CHECK_EMPTY and BOOST_PP_VA_OPT macros + add three more tools in the arsenal of macro programming, which is + a good thing, while programmers who wanted to ignore any dealing + with emptiness in macro code can continue to do so.
    See Also
    -
    -
    © Copyright - Edward Diener - 2019
    -
    -

    Distributed under the Boost Software License, - Version 1.0. - (See accompanying file LICENSE_1_0.txt - or copy at www.boost.org/LICENSE_1_0.txt)

    +
    +
    © Copyright Edward Diener 2019 +
    +
    +

    Distributed under the Boost Software License, Version + 1.0. (See accompanying file LICENSE_1_0.txt or + copy at www.boost.org/LICENSE_1_0.txt)

    - \ No newline at end of file +