220 7507 <CAPkOUVjGbUmcEwYUE_TDyiiGypedLd7YwdSZMfwRH5XEYTQooQ@mail.gmail.com> article
Path: news.gmane.org!not-for-mail
From: George Makrydakis <irrequietus@gmail.com>
Newsgroups: gmane.comp.lang.c++.isocpp.proposals
Subject: Re: Re: Proposal to standardize __VA_NARGS__
Date: Mon, 28 Oct 2013 21:09:21 +0200
Lines: 608
Approved: news@gmane.org
Message-ID: <CAPkOUVjGbUmcEwYUE_TDyiiGypedLd7YwdSZMfwRH5XEYTQooQ@mail.gmail.com>
References: <db18d21b-5633-404b-acfe-a5a37d985a38@isocpp.org>
	<3f298ed2-aa67-4fd5-928c-b97043fccf34@isocpp.org>
Reply-To: std-proposals@isocpp.org
NNTP-Posting-Host: plane.gmane.org
Mime-Version: 1.0
Content-Type: multipart/alternative; boundary=047d7b67888069529204e9d1d6a5
X-Trace: ger.gmane.org 1382987360 13101 80.91.229.3 (28 Oct 2013 19:09:20 GMT)
X-Complaints-To: usenet@ger.gmane.org
NNTP-Posting-Date: Mon, 28 Oct 2013 19:09:20 +0000 (UTC)
To: std-proposals@isocpp.org
Original-X-From: std-proposals+bncBDG4XBF6YIPBBYXMXKJQKGQELEW2I3I@isocpp.org Mon Oct 28 20:09:25 2013
Return-path: <std-proposals+bncBDG4XBF6YIPBBYXMXKJQKGQELEW2I3I@isocpp.org>
Envelope-to: gclcip-std-proposals@m.gmane.org
Original-Received: from mail-pb0-f72.google.com ([209.85.160.72])
	by plane.gmane.org with esmtp (Exim 4.69)
	(envelope-from <std-proposals+bncBDG4XBF6YIPBBYXMXKJQKGQELEW2I3I@isocpp.org>)
	id 1VasBo-0005qA-Cz
	for gclcip-std-proposals@m.gmane.org; Mon, 28 Oct 2013 20:09:24 +0100
Original-Received: by mail-pb0-f72.google.com with SMTP id jt11sf12837132pbb.7
        for <gclcip-std-proposals@m.gmane.org>; Mon, 28 Oct 2013 12:09:23 -0700 (PDT)
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=1e100.net; s=20130820;
        h=x-gm-message-state:mime-version:in-reply-to:references:date
         :message-id:subject:from:to:x-original-sender
         :x-original-authentication-results:reply-to:precedence:mailing-list
         :list-id:list-post:list-help:list-archive:list-subscribe
         :list-unsubscribe:content-type;
        bh=3igSZoeS3EBdPyLgOy8nXjoC2f4f/Jr404OtSMfvNac=;
        b=UspF07Qo7BMkWZjqfoDCIeBWrW9HZPvSgIKaN96JwSxujV6GlxqN85yBaSLQJ53zem
         ADa1dcnFXex/4/AmMYE8ruzcyOJA7z360ElXDQ6noUT7ddSTxYjTtHKJZaxXW7b0I8EN
         8JYnq+TB/Dvc+RG/4tvJ92KmI5yFiqCDN6p/0/cZ8Op1DJCPicRxe6JU09qKiIkVOr2i
         kBdmbG4ttMNw/PDX3TZnMlJNx1PxIUvQbgLOFTgiMSR/Ok0za76uwHobRJKHm7MXTFTz
         Kw8CRPn8r6KU0c9LLAJ7E/ALRoLvvvu2X9kRZLDs9097UuY1XMopyO8s348dehkl3Mo4
         FQtA==
X-Gm-Message-State: ALoCoQnQ+94Udn4d8LeooSYTNMl5KMs6JvlOOTCi7np4Fst3RVJMNMzGH1gCqopy2DJwPltULsYG
X-Received: by 10.66.146.136 with SMTP id tc8mr2850738pab.43.1382987363204;
        Mon, 28 Oct 2013 12:09:23 -0700 (PDT)
X-BeenThere: std-proposals@isocpp.org
Original-Received: by 10.50.7.41 with SMTP id g9ls1822378iga.19.gmail; Mon, 28 Oct 2013
 12:09:21 -0700 (PDT)
X-Received: by 10.68.190.103 with SMTP id gp7mr17728939pbc.74.1382987361684;
        Mon, 28 Oct 2013 12:09:21 -0700 (PDT)
Original-Received: from mail-pa0-x22b.google.com (mail-pa0-x22b.google.com [2607:f8b0:400e:c03::22b])
        by mx.google.com with ESMTPS id fk10si13761442pab.319.2013.10.28.12.09.21
        for <std-proposals@isocpp.org>
        (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128);
        Mon, 28 Oct 2013 12:09:21 -0700 (PDT)
Received-SPF: pass (google.com: domain of irrequietus@gmail.com designates 2607:f8b0:400e:c03::22b as permitted sender) client-ip=2607:f8b0:400e:c03::22b;
Original-Received: by mail-pa0-f43.google.com with SMTP id hz1so7615788pad.16
        for <std-proposals@isocpp.org>; Mon, 28 Oct 2013 12:09:21 -0700 (PDT)
X-Received: by 10.66.146.170 with SMTP id td10mr3744966pab.161.1382987361502;
 Mon, 28 Oct 2013 12:09:21 -0700 (PDT)
Original-Received: by 10.68.146.65 with HTTP; Mon, 28 Oct 2013 12:09:21 -0700 (PDT)
In-Reply-To: <3f298ed2-aa67-4fd5-928c-b97043fccf34@isocpp.org>
X-Original-Sender: irrequietus@gmail.com
X-Original-Authentication-Results: mx.google.com;       spf=pass (google.com:
 domain of irrequietus@gmail.com designates 2607:f8b0:400e:c03::22b as
 permitted sender) smtp.mail=irrequietus@gmail.com;       dkim=pass
 header.i=@gmail.com;       dmarc=pass (p=NONE dis=NONE) header.from=gmail.com
Precedence: list
Mailing-list: list std-proposals@isocpp.org; contact std-proposals+owners@isocpp.org
List-ID: <std-proposals.isocpp.org>
X-Google-Group-Id: 399137483710
List-Post: <http://groups.google.com/a/isocpp.org/group/std-proposals/post>, <mailto:std-proposals@isocpp.org>
List-Help: <http://support.google.com/a/isocpp.org/bin/topic.py?topic=25838>, <mailto:std-proposals+help@isocpp.org>
List-Archive: <http://groups.google.com/a/isocpp.org/group/std-proposals/>
List-Subscribe: <http://groups.google.com/a/isocpp.org/group/std-proposals/subscribe>,
 <mailto:std-proposals+subscribe@isocpp.org>
List-Unsubscribe: <http://groups.google.com/a/isocpp.org/group/std-proposals/subscribe>,
 <mailto:googlegroups-manage+399137483710+unsubscribe@googlegroups.com>
Xref: news.gmane.org gmane.comp.lang.c++.isocpp.proposals:7507
Archived-At: <http://permalink.gmane.org/gmane.comp.lang.c++.isocpp.proposals/7507>

--047d7b67888069529204e9d1d6a5
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable

On Mon, Oct 28, 2013 at 1:08 PM, <morwenn29@gmail.com> wrote:

> At first, I only proposed __VA_NARGS__ in order to standardize something
> that has already been written by dozens of programmers and which still
> often has some problems.
> My aim wasn't to propose a change that fundamental and that important, bu=
t
> of course, __VA_COMMA__ would be a nice and powerful feature, offering mu=
ch
> more to
> preprocessor programmers than what they already have.
> Having both would be somehow great, and improving code generation would b=
e
> kind of awesome :)
>

I agree with you conceptually.

I think that adding either or both of said identifiers for macros using the
ellipsis notation in their definition is at some point inevitable since it
would ease the preprocessor's transition to a more code - generating
friendly tool other than a plain text substitution workaround. The problem
however is not only which between the two allows an implementation of the
other, but also which between the two is the unambiguous one. This requires
some very meticulous reading of the standards involved. After reviewing the
matter I exposed in my initial post to this thread, I think we have reason
to believe that there are some problems with ambiguity that need to be
dealt with.


>
> I think George's big post could be turned into a proper paper: it's
> motivating enough!
>

Thanks for your heads up and enthousiasm, I really appreciate it!


> But, it would be post to present it to the C standard first, and it could
> be separated into two papers (__VA_NARGS__ and __VA_COMMA__); that way,
> having one of the
> ideas rejecting wouldn't automatically mean having the other rejected.
>

I think that more work should be done before presenting either of these
elsewhere to be honest and I am not convinced right now that they should be
made separate. I took the liberty of writing up another piece of code where
I try to study the behaviour of both and whether or not these two are
equivalent for building up various simple constructs to use with the
preprocessor.

In summary, __VA_NARGS__ and __VA_COMMA__ could be made "equivalent" for
what concerns deploying them in preprocessor constructs for detecting the
"empty" token (and even getting rid of the need for extensions like the ,
##__VA_ARGS__ one). This "equivalence" stems from both expanding to non -
empty tokens that cannot be used as identifiers by preprocessor macros and
therefore cannot trigger other macros arbitrarily when used within complex
preprocessor constructs.

The problem however lies in the uniqueness of the token either of these
builtin identifiers resolve to. C99 =A76.10.3p4 and C++11 =A716.3p4 intepre=
t
the empty token as a single token, thus *NOT* allowing an eventual
__VA_NARGS__ to expand to 0 (zero) when it is the single argument used in
the replacement list for the ellipsis notation. Since the empty token, is a
token, then __VA_NARGS__ would have no escape but to resolve to 1. That
would be ambiguous with a single non - empty argument being passed for code
flows past the preprocessor.

This is also illustrated in the case of a variadic macro invoked with ()
thus having __VA_NARGS__ expand to 0 but a macro with (,) - that is two
empty tokens - to 2, because that is the semantic intention of the comma. I
would find such a compromise difficult to approach because of its ambiguity
and "special treatment" status. __VA_COMMA__ on the other hand, it not
being a "digits" - token would allow the end user to interpret () and (,)
in a way compatible with his / her own programming flow when implementing a
beyond - naive recursive counter for the arguments easily, because of
__VA_COMMA__ being available. As such, __VA_COMMA__ would allow us to
continue to intepret the empty token the way it is intepreted by both
standards for such a long time.

Together with the fact that it deals away with the need for a (,
##__VA_ARGS__) extension, it would be a harmless, useful and unambiguous
addition. The following example is valid C++11 (and C99 of course !) and it
is full of comments detailing what I am studied on the matter. It is kind
of a long read... but I think it kind of helps the conceptual point I am
trying to make. There are several other details I have been thinking about,
but for the time being this is more than enough. Comments are very welcome.

[segment begins]

#include <cstdio>
/** * Please compile with -Werror -Wall -Wextra -std=3Dc++11 -pedantic
(very strict!) *  * A check for the empty preprocessor token in C++11.
Notice the implementation * of MACRO_EMPTY(...). This is valid code
for demonstrational purposes. *  * In said macro, __VA_ARGS__ could be
substituted by either of the eventual * __VA_NARGS__ or __VA_COMMA__
identifiers. Either of said identifiers could * exist in the
replacement list of a function - like macro that uses the * ellipsis
notation in its definition. While __VA_COMMA__ expands to a single *
comma if and only if __VA_ARGS__ does not expand to the empty token,
the * __VA_NARGS__ would expand to a token consisting only of decimal
digits and * representing the number of comma separated tokens to
which __VA_ARGS__ * expands to. *  *
---------------------------------------------------------------------------=
-
* The macro that would be best served by either of these is
MACRO_EMPTY(...) * and thus its writing would be greately simplified :
*  * (a) using __VA_NARGS__ : *  *      #define MACRO_EMPTY(...) \ *
           MACRO_EMPTY_1(MACRO_EMPTY_0 __VA_NARGS__ ()) *  * (b) using
__VA_COMMA__ : *  *      #define MACRO_EMPTY(...) \ *
MACRO_EMPTY_1(MACRO_EMPTY_0 __VA_COMMA__ ()) *  *
---------------------------------------------------------------------------=
-
*  * (1) "Last token is a function macro in __VA_ARGS__" is an issue
both *     identifiers (__VA_NARGS__ and __VA_COMMA__) deal with
reducing the amount *     of constructs necessary when checking for
the empty preprocessor token. *  * Notice that if the last token in
__VA_ARGS__ is a defined function macro, * the balanced parenthesis
token following it would result in invoking said * macro, therefore
providing unexpected results. Current ways of bypassing * this
particular problem are available requiring greater complexity in * the
preprocessor constructs involved but are not presented here because
they * are out of the purpose of this demonstration. *  * (2) "First
token is a balanced parenthesis in __VA_ARGS__" is an issue both *
identifiers (__VA_NARGS__ and __VA_COMMA__) deal with reducing the
amount *     of constructs necessary when checking for the empty
preprocessor token. *  * (3) __VA_NARGS__ and __VA_COMMA__ are
equivalent for their primary purposes *    but both require additional
preprocessor metaprogramming constructs when *    used for detecting
__VA_ARGS__ expansion to the empty preprocessor token. *  * If the
hypothetical __VA_NARGS__ identifier was used, it would yield a token
* starting with a digit, thus invocation of MACRO_EMPTY_0 would not
occur. The * same holds for the hypothetical __VA_COMMA__. Both
expansions of said * identifiers yield tokens that could have not been
used as identifiers * themselves (that is in #define statements) thus
resolving the "last token * is a function macro in __VA_ARGS__" issue
as presented in (1). *  * (4) __VA_COMMA__ by definition expands only
to a single comma if and only if *     __VA_ARGS__ does not expand to
the empty token which means that it has *     unambiguous meaning over
__VA_NARGS__ when it comes to handling said *     token, due to the
definition of the "no arguments" token in C99 =A76.10.3p4 *     and
C++11 =A716.3p4. Thus, the notational advantage of __VA_NARGS__ in *
providing argument count *  *  This means that __VA_NARGS__ can have
different meanings for code constructs *  out of the realm of the
preprocessor when it comes to assuming the value *  "1" for both a
single token (no commas) and the empty token. __VA_COMMA__ *
expansion *is* the empty token unambiguously if and only if
__VA_ARGS__ is, *  in all other cases it expands to a comma. *  * (5)
__VA_COMMA__ takes away the need for a (, ##__VA_ARGS__) extension
with *     no additional constructs required, while __VA_NARGS__
requires them in *     order to do so but may be ambiguous because of
(4). *  *     __VA__COMMA__ __VA_ARGS__  : a comma precedes
__VA_ARGS__ if and only if *
__VA_ARGS__ does not expand to the empty *
     preprocessor token. *  *     X(__VA_NARGS__) __VA_ARGS__: X would
have to be a macro that would *
expand to a comma if __VA_NARGS__ was 0, *
     but because of (4) such a macro may be *
        unfeasible to implement if __VA_NARGS__ *
            has to resolve to the minimum of "1". *  */
#define MACRO_0 0#define MACRO_1 1,#define MACRO_EMPTY_0() 1,#define
MACRO_MACRO_EMPTY_0 0,#define MACRO_EMPTY_1(...)
MACRO_EMPTY_2(__VA_ARGS__)#define MACRO_EMPTY_2(...)
MACRO_EMPTY_3(MACRO_ ## __VA_ARGS__)#define MACRO_EMPTY_3(...)
MACRO_EMPTY_4(__VA_ARGS__)#define MACRO_EMPTY_4(x,...) x#define
MACRO_EMPTY_5() 0,#define MACRO_MACRO_EMPTY_5 1,#define
MACRO_EMPTY_6(x,y) MACRO_EMPTY_7(x,y)#define MACRO_EMPTY_7(x,y)
MACRO_EMPTY_##x##y()
/* This is an implementation of the AND logic gate */
#define MACRO_EMPTY_00() 0#define MACRO_EMPTY_10() 0#define
MACRO_EMPTY_11() 1#define MACRO_EMPTY_01() 0
/** * The actual macro for checking for the "empty" token provided (1)
does not * apply, because (1) would require a more complicated version
and of course * is what __VA_NARGS__ / __VA_COMMA__ would deal with
best, making a lot of * the macros defined above pointless. */#define
MACRO_EMPTY(...) \        MACRO_EMPTY_6( MACRO_EMPTY_1(MACRO_EMPTY_0
__VA_ARGS__ ()) \                     , MACRO_EMPTY_1(MACRO_EMPTY_5
__VA_ARGS__,) )
/** * Using string concatenation for implementing an expression
evaluation of * sorts, preprocessor - wise. Combining the following
with a recursion and * an addition construct can yield the number of
tokens in a comma separated * list of preprocessor tokens. This means
that at a cost, __VA_NARGS__ could * be implemented as VA_NARGS(...)
using preprocessor metaprogramming. The * techniques involved for this
vary, but outside naive implementations require * few lines for
several hundred (and more) tokens to be accounted for. */#define
MACRO_IFELSE(x,y,z)  MACRO_IFELSE_(x,y,z)#define MACRO_IFELSE_(x,y,z)
MACRO_IFELSE##x(y,z)#define MACRO_IFELSE1(y,z) y#define
MACRO_IFELSE0(y,z) z
int main() {

    // full !
    printf("%s\n"  , MACRO_IFELSE(MACRO_EMPTY(a),"null","full"));
    printf("%s\n"  , MACRO_IFELSE(MACRO_EMPTY(a,b),"null","full"));
    printf("%s\n"  , MACRO_IFELSE(MACRO_EMPTY(,),"null","full"));
    printf("%s\n"  , MACRO_IFELSE(MACRO_EMPTY(()),"null","full"));
    printf("%s\n"  , MACRO_IFELSE(MACRO_EMPTY(+),"null","full"));
    printf("%s\n"  , MACRO_IFELSE(MACRO_EMPTY([]),"null","full"));
    printf("%s\n\n", MACRO_IFELSE(MACRO_EMPTY(!),"null","full"));

    // null, i.e. the empty token, which is actually "argument count 1" for=
 what
    // the preprocessor is concerned but that not may always be for what th=
e
    // end user is concerned. __VA_COMMA__ has an advantage over such an
    // occasion as well since it would allow the end user to take that
    // decision for his / her own needs.
    printf("%s\n", MACRO_IFELSE(MACRO_EMPTY(/**/),"null","full"));
    printf("%s\n", MACRO_IFELSE(MACRO_EMPTY(),"null","full"));

    *return* {};
}


[segment ends]

--=20

---=20
You received this message because you are subscribed to the Google Groups "=
ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposa=
ls/.

--047d7b67888069529204e9d1d6a5
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr">On Mon, Oct 28, 2013 at 1:08 PM,  <span dir=3D"ltr">&lt;<a=
 href=3D"mailto:morwenn29@gmail.com" target=3D"_blank">morwenn29@gmail.com<=
/a>&gt;</span> wrote:<br><div class=3D"gmail_extra"><div class=3D"gmail_quo=
te"><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;bor=
der-left:1px solid rgb(204,204,204);padding-left:1ex">
<div dir=3D"ltr">At first, I only proposed __VA_NARGS__ in order to standar=
dize something that has already been written by dozens of programmers and w=
hich still often has some problems.<br>My aim wasn&#39;t to propose a chang=
e that fundamental and that important, but of course, __VA_COMMA__ would be=
 a nice and powerful feature, offering much more to<br>
preprocessor programmers than what they already have.<br>Having both would =
be somehow great, and improving code generation would be kind of awesome :)=
<br></div></blockquote><div><br>I agree with you conceptually.<br><br>I thi=
nk that adding either or both of said identifiers for macros using the elli=
psis notation in their definition is at some point inevitable since it woul=
d ease the preprocessor&#39;s transition to a more code - generating friend=
ly tool other than a plain text substitution workaround. The problem howeve=
r is not only which between the two allows an implementation of the other, =
but also which between the two is the unambiguous one. This requires some v=
ery meticulous reading of the standards involved. After reviewing the matte=
r I exposed in my initial post to this thread, I think we have reason to be=
lieve that there are some problems with ambiguity that need to be dealt wit=
h.<br>
</div><div>=A0</div><blockquote class=3D"gmail_quote" style=3D"margin:0px 0=
px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div =
dir=3D"ltr"><br>I think George&#39;s big post could be turned into a proper=
 paper: it&#39;s motivating enough!<br>
</div></blockquote><div><br>Thanks for your heads up and enthousiasm, I rea=
lly appreciate it!<br>=A0<br></div><blockquote class=3D"gmail_quote" style=
=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding=
-left:1ex">
<div dir=3D"ltr">But, it would be post to present it to the C standard firs=
t, and it could be separated into two papers (__VA_NARGS__ and __VA_COMMA__=
); that way, having one of the<br>ideas rejecting wouldn&#39;t automaticall=
y mean having the other rejected.<br>
</div></blockquote><div><br></div><div>I think that more work should be don=
e before presenting either of these elsewhere to be honest and I am not con=
vinced right now that they should be made separate. I took the liberty of w=
riting up another piece of code where I try to study the behaviour of both =
and whether or not these two are equivalent for building up various simple =
constructs to use with the preprocessor.<br>
<br></div><div>In summary, __VA_NARGS__ and __VA_COMMA__ could be made &quo=
t;equivalent&quot; for what concerns deploying them in preprocessor constru=
cts for detecting the &quot;empty&quot; token (and even getting rid of the =
need for extensions like the , ##__VA_ARGS__ one). This &quot;equivalence&q=
uot; stems from both expanding to non - empty tokens that cannot be used as=
 identifiers by preprocessor macros and therefore cannot trigger other macr=
os arbitrarily when used within complex preprocessor constructs.<br>
<br>The problem however lies in the uniqueness of the token either of these=
 builtin identifiers resolve to. C99 =A76.10.3p4 and C++11 =A716.3p4 intepr=
et the empty token as a single token, thus <b>NOT</b> allowing an eventual =
__VA_NARGS__ to expand to 0 (zero) when it is the single argument used in t=
he replacement list for the ellipsis notation. Since the empty token, is a =
token, then __VA_NARGS__ would have no escape but to resolve to 1. That wou=
ld be ambiguous with a single non - empty argument being passed for code fl=
ows past the preprocessor.<br>
<br>This is also illustrated in the case of a variadic macro invoked with (=
) thus having __VA_NARGS__ expand to 0 but a macro with (,) - that is two e=
mpty tokens - to 2, because that is the semantic intention of the comma. I =
would find such a compromise difficult to approach because of its ambiguity=
 and &quot;special treatment&quot; status. __VA_COMMA__ on the other hand, =
it not being a &quot;digits&quot; - token would allow the end user to inter=
pret () and (,) in a way compatible with his / her own programming flow whe=
n implementing a beyond - naive recursive counter for the arguments easily,=
 because of __VA_COMMA__ being available. As such, __VA_COMMA__ would allow=
 us to continue to intepret the empty token the way it is intepreted by bot=
h standards for such a long time.<br>
<br>Together with the fact that it deals away with the need for a (, ##__VA=
_ARGS__) extension, it would be a harmless, useful and unambiguous addition=
.. The following example is valid C++11 (and C99 of course !) and it is full=
 of comments=20
detailing what I am studied on the matter. It is kind of a long read... but=
 I think it kind of helps the conceptual point I am trying to make. There a=
re several other details I have been thinking about, but for the time being=
 this is more than enough. Comments are very welcome.<br>
<br></div><div>[segment begins]<br></div><div><pre style=3D"color:rgb(31,28=
,27);background-color:rgb(255,255,255)"><span style=3D"color:rgb(7,47,87)">=
#include </span><span style=3D"color:rgb(7,47,87)">&lt;cstdio&gt;</span>

<span style=3D"color:rgb(137,136,135)">/**</span>
<span style=3D"color:rgb(137,136,135)"> * Please compile with -Werror -Wall=
 -Wextra -std=3Dc++11 -pedantic (very strict!)</span>
<span style=3D"color:rgb(137,136,135)"> * </span>
<span style=3D"color:rgb(137,136,135)"> * A check for the empty preprocesso=
r token in C++11. Notice the implementation</span>
<span style=3D"color:rgb(137,136,135)"> * of MACRO_EMPTY(...). This is vali=
d code for demonstrational purposes.</span>
<span style=3D"color:rgb(137,136,135)"> * </span>
<span style=3D"color:rgb(137,136,135)"> * In said macro, __VA_ARGS__ could =
be substituted by either of the eventual</span>
<span style=3D"color:rgb(137,136,135)"> * __VA_NARGS__ or __VA_COMMA__ iden=
tifiers. Either of said identifiers could</span>
<span style=3D"color:rgb(137,136,135)"> * exist in the replacement list of =
a function - like macro that uses the</span>
<span style=3D"color:rgb(137,136,135)"> * ellipsis notation in its definiti=
on. While __VA_COMMA__ expands to a single</span>
<span style=3D"color:rgb(137,136,135)"> * comma if and only if __VA_ARGS__ =
does not expand to the empty token, the</span>
<span style=3D"color:rgb(137,136,135)"> * __VA_NARGS__ would expand to a to=
ken consisting only of decimal digits and</span>
<span style=3D"color:rgb(137,136,135)"> * representing the number of comma =
separated tokens to which __VA_ARGS__</span>
<span style=3D"color:rgb(137,136,135)"> * expands to.</span>
<span style=3D"color:rgb(137,136,135)"> * </span>
<span style=3D"color:rgb(137,136,135)"> * ---------------------------------=
-------------------------------------------</span>
<span style=3D"color:rgb(137,136,135)"> * The macro that would be best serv=
ed by either of these is MACRO_EMPTY(...)</span>
<span style=3D"color:rgb(137,136,135)"> * and thus its writing would be gre=
ately simplified :</span>
<span style=3D"color:rgb(137,136,135)"> * </span>
<span style=3D"color:rgb(137,136,135)"> * (a) using __VA_NARGS__ :</span>
<span style=3D"color:rgb(137,136,135)"> * </span>
<span style=3D"color:rgb(137,136,135)"> *      #define MACRO_EMPTY(...) \</=
span>
<span style=3D"color:rgb(137,136,135)"> *              MACRO_EMPTY_1(MACRO_=
EMPTY_0 __VA_NARGS__ ())</span>
<span style=3D"color:rgb(137,136,135)"> * </span>
<span style=3D"color:rgb(137,136,135)"> * (b) using __VA_COMMA__ :</span>
<span style=3D"color:rgb(137,136,135)"> * </span>
<span style=3D"color:rgb(137,136,135)"> *      #define MACRO_EMPTY(...) \</=
span>
<span style=3D"color:rgb(137,136,135)"> *              MACRO_EMPTY_1(MACRO_=
EMPTY_0 __VA_COMMA__ ())</span>
<span style=3D"color:rgb(137,136,135)"> * </span>
<span style=3D"color:rgb(137,136,135)"> * ---------------------------------=
-------------------------------------------</span>
<span style=3D"color:rgb(137,136,135)"> * </span>
<span style=3D"color:rgb(137,136,135)"> * (1) &quot;Last token is a functio=
n macro in __VA_ARGS__&quot; is an issue both</span>
<span style=3D"color:rgb(137,136,135)"> *     identifiers (__VA_NARGS__ and=
 __VA_COMMA__) deal with reducing the amount</span>
<span style=3D"color:rgb(137,136,135)"> *     of constructs necessary when =
checking for the empty preprocessor token.</span>
<span style=3D"color:rgb(137,136,135)"> * </span>
<span style=3D"color:rgb(137,136,135)"> * Notice that if the last token in =
__VA_ARGS__ is a defined function macro,</span>
<span style=3D"color:rgb(137,136,135)"> * the balanced parenthesis token fo=
llowing it would result in invoking said</span>
<span style=3D"color:rgb(137,136,135)"> * macro, therefore providing unexpe=
cted results. Current ways of bypassing</span>
<span style=3D"color:rgb(137,136,135)"> * this particular problem are avail=
able requiring greater complexity in</span>
<span style=3D"color:rgb(137,136,135)"> * the preprocessor constructs invol=
ved but are not presented here because they</span>
<span style=3D"color:rgb(137,136,135)"> * are out of the purpose of this de=
monstration.</span>
<span style=3D"color:rgb(137,136,135)"> * </span>
<span style=3D"color:rgb(137,136,135)"> * (2) &quot;First token is a balanc=
ed parenthesis in __VA_ARGS__&quot; is an issue both</span>
<span style=3D"color:rgb(137,136,135)"> *     identifiers (__VA_NARGS__ and=
 __VA_COMMA__) deal with reducing the amount</span>
<span style=3D"color:rgb(137,136,135)"> *     of constructs necessary when =
checking for the empty preprocessor token.</span>
<span style=3D"color:rgb(137,136,135)"> * </span>
<span style=3D"color:rgb(137,136,135)"> * (3) __VA_NARGS__ and __VA_COMMA__=
 are equivalent for their primary purposes</span>
<span style=3D"color:rgb(137,136,135)"> *    but both require additional pr=
eprocessor metaprogramming constructs when</span>
<span style=3D"color:rgb(137,136,135)"> *    used for detecting __VA_ARGS__=
 expansion to the empty preprocessor token.</span>
<span style=3D"color:rgb(137,136,135)"> * </span>
<span style=3D"color:rgb(137,136,135)"> * If the hypothetical __VA_NARGS__ =
identifier was used, it would yield a token</span>
<span style=3D"color:rgb(137,136,135)"> * starting with a digit, thus invoc=
ation of MACRO_EMPTY_0 would not occur. The</span>
<span style=3D"color:rgb(137,136,135)"> * same holds for the hypothetical _=
_VA_COMMA__. Both expansions of said</span>
<span style=3D"color:rgb(137,136,135)"> * identifiers yield tokens that cou=
ld have not been used as identifiers</span>
<span style=3D"color:rgb(137,136,135)"> * themselves (that is in #define st=
atements) thus resolving the &quot;last token</span>
<span style=3D"color:rgb(137,136,135)"> * is a function macro in __VA_ARGS_=
_&quot; issue as presented in (1).</span>
<span style=3D"color:rgb(137,136,135)"> * </span>
<span style=3D"color:rgb(137,136,135)"> * (4) __VA_COMMA__ by definition ex=
pands only to a single comma if and only if</span>
<span style=3D"color:rgb(137,136,135)"> *     __VA_ARGS__ does not expand t=
o the empty token which means that it has</span>
<span style=3D"color:rgb(137,136,135)"> *     unambiguous meaning over __VA=
_NARGS__ when it comes to handling said</span>
<span style=3D"color:rgb(137,136,135)"> *     token, due to the definition =
of the &quot;no arguments&quot; token in C99 =A76.10.3p4</span>
<span style=3D"color:rgb(137,136,135)"> *     and C++11 =A716.3p4. Thus, th=
e notational advantage of __VA_NARGS__ in</span>
<span style=3D"color:rgb(137,136,135)"> *     providing argument count</spa=
n>
<span style=3D"color:rgb(137,136,135)"> * </span>
<span style=3D"color:rgb(137,136,135)"> *  This means that __VA_NARGS__ can=
 have different meanings for code constructs</span>
<span style=3D"color:rgb(137,136,135)"> *  out of the realm of the preproce=
ssor when it comes to assuming the value</span>
<span style=3D"color:rgb(137,136,135)"> *  &quot;1&quot; for both a single =
token (no commas) and the empty token. __VA_COMMA__</span>
<span style=3D"color:rgb(137,136,135)"> *  expansion *is* the empty token u=
nambiguously if and only if __VA_ARGS__ is,</span>
<span style=3D"color:rgb(137,136,135)"> *  in all other cases it expands to=
 a comma.</span>
<span style=3D"color:rgb(137,136,135)"> * </span>
<span style=3D"color:rgb(137,136,135)"> * (5) __VA_COMMA__ takes away the n=
eed for a (, ##__VA_ARGS__) extension with</span>
<span style=3D"color:rgb(137,136,135)"> *     no additional constructs requ=
ired, while __VA_NARGS__ requires them in</span>
<span style=3D"color:rgb(137,136,135)"> *     order to do so but may be amb=
iguous because of (4).</span>
<span style=3D"color:rgb(137,136,135)"> * </span>
<span style=3D"color:rgb(137,136,135)"> *     __VA__COMMA__ __VA_ARGS__  : =
a comma precedes __VA_ARGS__ if and only if</span>
<span style=3D"color:rgb(137,136,135)"> *                                  =
__VA_ARGS__ does not expand to the empty</span>
<span style=3D"color:rgb(137,136,135)"> *                                  =
preprocessor token.</span>
<span style=3D"color:rgb(137,136,135)"> * </span>
<span style=3D"color:rgb(137,136,135)"> *     X(__VA_NARGS__) __VA_ARGS__: =
X would have to be a macro that would</span>
<span style=3D"color:rgb(137,136,135)"> *                                  =
expand to a comma if __VA_NARGS__ was 0,</span>
<span style=3D"color:rgb(137,136,135)"> *                                  =
but because of (4) such a macro may be</span>
<span style=3D"color:rgb(137,136,135)"> *                                  =
unfeasible to implement if __VA_NARGS__</span>
<span style=3D"color:rgb(137,136,135)"> *                                  =
has to resolve to the minimum of &quot;1&quot;.</span>
<span style=3D"color:rgb(137,136,135)"> * </span>
<span style=3D"color:rgb(137,136,135)"> */</span>

<span style=3D"color:rgb(7,47,87)">#define MACRO_0 0</span>
<span style=3D"color:rgb(7,47,87)">#define MACRO_1 1,</span>
<span style=3D"color:rgb(7,47,87)">#define MACRO_EMPTY_0() 1,</span>
<span style=3D"color:rgb(7,47,87)">#define MACRO_MACRO_EMPTY_0 0,</span>
<span style=3D"color:rgb(7,47,87)">#define MACRO_EMPTY_1(...) MACRO_EMPTY_2=
(__VA_ARGS__)</span>
<span style=3D"color:rgb(7,47,87)">#define MACRO_EMPTY_2(...) MACRO_EMPTY_3=
(MACRO_ ## __VA_ARGS__)</span>
<span style=3D"color:rgb(7,47,87)">#define MACRO_EMPTY_3(...) MACRO_EMPTY_4=
(__VA_ARGS__)</span>
<span style=3D"color:rgb(7,47,87)">#define MACRO_EMPTY_4(x,...) x</span>
<span style=3D"color:rgb(7,47,87)">#define MACRO_EMPTY_5() 0,</span>
<span style=3D"color:rgb(7,47,87)">#define MACRO_MACRO_EMPTY_5 1,</span>
<span style=3D"color:rgb(7,47,87)">#define MACRO_EMPTY_6(x,y) MACRO_EMPTY_7=
(x,y)</span>
<span style=3D"color:rgb(7,47,87)">#define MACRO_EMPTY_7(x,y) MACRO_EMPTY_#=
#x##y()</span>

<span style=3D"color:rgb(137,136,135)">/* This is an implementation of the =
AND logic gate */</span>

<span style=3D"color:rgb(7,47,87)">#define MACRO_EMPTY_00() 0</span>
<span style=3D"color:rgb(7,47,87)">#define MACRO_EMPTY_10() 0</span>
<span style=3D"color:rgb(7,47,87)">#define MACRO_EMPTY_11() 1</span>
<span style=3D"color:rgb(7,47,87)">#define MACRO_EMPTY_01() 0</span>

<span style=3D"color:rgb(137,136,135)">/**</span>
<span style=3D"color:rgb(137,136,135)"> * The actual macro for checking for=
 the &quot;empty&quot; token provided (1) does not</span>
<span style=3D"color:rgb(137,136,135)"> * apply, because (1) would require =
a more complicated version and of course</span>
<span style=3D"color:rgb(137,136,135)"> * is what __VA_NARGS__ / __VA_COMMA=
__ would deal with best, making a lot of</span>
<span style=3D"color:rgb(137,136,135)"> * the macros defined above pointles=
s.</span>
<span style=3D"color:rgb(137,136,135)"> */</span>
<span style=3D"color:rgb(7,47,87)">#define MACRO_EMPTY(...) \</span>
<span style=3D"color:rgb(7,47,87)">        MACRO_EMPTY_6( MACRO_EMPTY_1(MAC=
RO_EMPTY_0 __VA_ARGS__ ()) \</span>
<span style=3D"color:rgb(7,47,87)">                     , MACRO_EMPTY_1(MAC=
RO_EMPTY_5 __VA_ARGS__,) )</span>

<span style=3D"color:rgb(137,136,135)">/**</span>
<span style=3D"color:rgb(137,136,135)"> * Using string concatenation for im=
plementing an expression evaluation of</span>
<span style=3D"color:rgb(137,136,135)"> * sorts, preprocessor - wise. Combi=
ning the following with a recursion and</span>
<span style=3D"color:rgb(137,136,135)"> * an addition construct can yield t=
he number of tokens in a comma separated</span>
<span style=3D"color:rgb(137,136,135)"> * list of preprocessor tokens. This=
 means that at a cost, __VA_NARGS__ could</span>
<span style=3D"color:rgb(137,136,135)"> * be implemented as VA_NARGS(...) u=
sing preprocessor metaprogramming. The</span>
<span style=3D"color:rgb(137,136,135)"> * techniques involved for this vary=
, but outside naive implementations require</span>
<span style=3D"color:rgb(137,136,135)"> * few lines for several hundred (an=
d more) tokens to be accounted for.</span>
<span style=3D"color:rgb(137,136,135)"> */</span>
<span style=3D"color:rgb(7,47,87)">#define MACRO_IFELSE(x,y,z)  MACRO_IFELS=
E_(x,y,z)</span>
<span style=3D"color:rgb(7,47,87)">#define MACRO_IFELSE_(x,y,z) MACRO_IFELS=
E##x(y,z)</span>
<span style=3D"color:rgb(7,47,87)">#define MACRO_IFELSE1(y,z) y</span>
<span style=3D"color:rgb(7,47,87)">#define MACRO_IFELSE0(y,z) z</span>

<span style=3D"color:rgb(0,87,174)">int</span> main() {

    <span style=3D"color:rgb(137,136,135)">// full !</span>
    printf(<span style=3D"color:rgb(191,3,3)">&quot;%s</span><span style=3D=
"color:rgb(146,76,157)">\n</span><span style=3D"color:rgb(191,3,3)">&quot;<=
/span>  , MACRO_IFELSE(MACRO_EMPTY(a),<span style=3D"color:rgb(191,3,3)">&q=
uot;null&quot;</span>,<span style=3D"color:rgb(191,3,3)">&quot;full&quot;</=
span>));
    printf(<span style=3D"color:rgb(191,3,3)">&quot;%s</span><span style=3D=
"color:rgb(146,76,157)">\n</span><span style=3D"color:rgb(191,3,3)">&quot;<=
/span>  , MACRO_IFELSE(MACRO_EMPTY(a,b),<span style=3D"color:rgb(191,3,3)">=
&quot;null&quot;</span>,<span style=3D"color:rgb(191,3,3)">&quot;full&quot;=
</span>));
    printf(<span style=3D"color:rgb(191,3,3)">&quot;%s</span><span style=3D=
"color:rgb(146,76,157)">\n</span><span style=3D"color:rgb(191,3,3)">&quot;<=
/span>  , MACRO_IFELSE(MACRO_EMPTY(,),<span style=3D"color:rgb(191,3,3)">&q=
uot;null&quot;</span>,<span style=3D"color:rgb(191,3,3)">&quot;full&quot;</=
span>));
    printf(<span style=3D"color:rgb(191,3,3)">&quot;%s</span><span style=3D=
"color:rgb(146,76,157)">\n</span><span style=3D"color:rgb(191,3,3)">&quot;<=
/span>  , MACRO_IFELSE(MACRO_EMPTY(()),<span style=3D"color:rgb(191,3,3)">&=
quot;null&quot;</span>,<span style=3D"color:rgb(191,3,3)">&quot;full&quot;<=
/span>));
    printf(<span style=3D"color:rgb(191,3,3)">&quot;%s</span><span style=3D=
"color:rgb(146,76,157)">\n</span><span style=3D"color:rgb(191,3,3)">&quot;<=
/span>  , MACRO_IFELSE(MACRO_EMPTY(+),<span style=3D"color:rgb(191,3,3)">&q=
uot;null&quot;</span>,<span style=3D"color:rgb(191,3,3)">&quot;full&quot;</=
span>));
    printf(<span style=3D"color:rgb(191,3,3)">&quot;%s</span><span style=3D=
"color:rgb(146,76,157)">\n</span><span style=3D"color:rgb(191,3,3)">&quot;<=
/span>  , MACRO_IFELSE(MACRO_EMPTY([]),<span style=3D"color:rgb(191,3,3)">&=
quot;null&quot;</span>,<span style=3D"color:rgb(191,3,3)">&quot;full&quot;<=
/span>));
    printf(<span style=3D"color:rgb(191,3,3)">&quot;%s</span><span style=3D=
"color:rgb(146,76,157)">\n\n</span><span style=3D"color:rgb(191,3,3)">&quot=
;</span>, MACRO_IFELSE(MACRO_EMPTY(!),<span style=3D"color:rgb(191,3,3)">&q=
uot;null&quot;</span>,<span style=3D"color:rgb(191,3,3)">&quot;full&quot;</=
span>));

    <span style=3D"color:rgb(137,136,135)">// null, i.e. the empty token, w=
hich is actually &quot;argument count 1&quot; for what</span>
    <span style=3D"color:rgb(137,136,135)">// the preprocessor is concerned=
 but that not may always be for what the</span>
    <span style=3D"color:rgb(137,136,135)">// end user is concerned. __VA_C=
OMMA__ has an advantage over such an</span>
    <span style=3D"color:rgb(137,136,135)">// occasion as well since it wou=
ld allow the end user to take that</span>
    <span style=3D"color:rgb(137,136,135)">// decision for his / her own ne=
eds.</span>
    printf(<span style=3D"color:rgb(191,3,3)">&quot;%s</span><span style=3D=
"color:rgb(146,76,157)">\n</span><span style=3D"color:rgb(191,3,3)">&quot;<=
/span>, MACRO_IFELSE(MACRO_EMPTY(<span style=3D"color:rgb(137,136,135)">/**=
/</span>),<span style=3D"color:rgb(191,3,3)">&quot;null&quot;</span>,<span =
style=3D"color:rgb(191,3,3)">&quot;full&quot;</span>));
    printf(<span style=3D"color:rgb(191,3,3)">&quot;%s</span><span style=3D=
"color:rgb(146,76,157)">\n</span><span style=3D"color:rgb(191,3,3)">&quot;<=
/span>, MACRO_IFELSE(MACRO_EMPTY(),<span style=3D"color:rgb(191,3,3)">&quot=
;null&quot;</span>,<span style=3D"color:rgb(191,3,3)">&quot;full&quot;</spa=
n>));

    <b>return</b> {};
}

</pre>[segment ends]<br></div></div><br></div></div>

<p></p>

-- <br />
&nbsp;<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals&quot; group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.<br />
To post to this group, send email to std-proposals@isocpp.org.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />

--047d7b67888069529204e9d1d6a5--

.
