Ok,
I see that there are 3 ways of doing this now. What is the
recommendation for something small like 2 or 3 lines for each native
types i.e. more or less 12 iterations?
Eric
"Paul Mensonides"
Tanton Gibbs wrote:
You can use BOOST_PP_LIST_FOR_EACH
#define ARG_LIST (char, (int, (unsigned int, (long, ...)))) #define DO_IT(r, data, elem) void foo( elem );
BOOST_PP_LIST_FOR_EACH( DO_IT, , ARG_LIST ) ^ This empty argument is undefined in C++. In C99, it is allowed and called a "placemarker." Instead of passing nothing, just pass anything and ignore it.
// ----- //
#include
#define ARG_LIST \ (char, (int, (unsigned, (long, BOOST_PP_NIL)))) \ /**/ #define DO_IT(r, ignored, elem) \ void foo( elem ); \ /**/
BOOST_PP_LIST_FOR_EACH( DO_IT, ?, ARG_LIST )
#undef ARG_LIST #undef DO_IT
// ----- //
Note that there are other ways to do this also. For instance, use of "sequences" makes the definition of ARG_LIST easier:
// ----- //
#include
#define ARGS \ (char)(int)(unsigned)(long) \ /**/ #define DO_IT(r, ignored, elem) \ void foo( elem ); \ /**/
BOOST_PP_SEQ_FOR_EACH( DO_IT, ?, ARGS )
#undef ARGS #undef DO_IT
// ----- //
Of course, if what you want to generate is much larger, you might want to use some form of vertical repetition:
// ----- //
#include
#include #define ARGS \ (char)(int)(unsigned)(long) \ /**/
#define BOOST_PP_LOCAL_MACRO(n) \ void foo( BOOST_PP_SEQ_ELEM(n, ARGS) ); \ /**/ #define BOOST_PP_LOCAL_LIMITS \ (0, BOOST_PP_SEQ_SIZE(ARGS) - 1) \ /**/ #include BOOST_PP_LOCAL_ITERATE()
#undef ARGS
// ----- //
Regards, Paul Mensonides
[Non-text portions of this message have been removed]
Also, I was asked by a coworker if the following would be std C++:
BOOST_PP_LIST_FOR_EACH( DO_IT, BOOST_PP_EMPTY(), ARG_LIST )
I said that it would not because BOOST_PP_EMPTY would be expanded first to
nothing, which would be the same as
BOOST_PP_LIST_FOR_EACH( DO_IT, , ARG_LIST )
which Paul explicitly said below was non-conformant.
Is this correct?
----- Original Message -----
From: "Eric Robert"
Ok, I see that there are 3 ways of doing this now. What is the recommendation for something small like 2 or 3 lines for each native types i.e. more or less 12 iterations?
Eric
"Paul Mensonides"
wrote Tanton Gibbs wrote:
You can use BOOST_PP_LIST_FOR_EACH
#define ARG_LIST (char, (int, (unsigned int, (long, ...)))) #define DO_IT(r, data, elem) void foo( elem );
BOOST_PP_LIST_FOR_EACH( DO_IT, , ARG_LIST ) ^ This empty argument is undefined in C++. In C99, it is allowed and called a "placemarker." Instead of passing nothing, just pass anything and ignore it.
// ----- //
#include
#define ARG_LIST \ (char, (int, (unsigned, (long, BOOST_PP_NIL)))) \ /**/ #define DO_IT(r, ignored, elem) \ void foo( elem ); \ /**/
BOOST_PP_LIST_FOR_EACH( DO_IT, ?, ARG_LIST )
#undef ARG_LIST #undef DO_IT
// ----- //
Note that there are other ways to do this also. For instance, use of "sequences" makes the definition of ARG_LIST easier:
// ----- //
#include
#define ARGS \ (char)(int)(unsigned)(long) \ /**/ #define DO_IT(r, ignored, elem) \ void foo( elem ); \ /**/
BOOST_PP_SEQ_FOR_EACH( DO_IT, ?, ARGS )
#undef ARGS #undef DO_IT
// ----- //
Of course, if what you want to generate is much larger, you might want to use some form of vertical repetition:
// ----- //
#include
#include #define ARGS \ (char)(int)(unsigned)(long) \ /**/
#define BOOST_PP_LOCAL_MACRO(n) \ void foo( BOOST_PP_SEQ_ELEM(n, ARGS) ); \ /**/ #define BOOST_PP_LOCAL_LIMITS \ (0, BOOST_PP_SEQ_SIZE(ARGS) - 1) \ /**/ #include BOOST_PP_LOCAL_ITERATE()
#undef ARGS
// ----- //
Regards, Paul Mensonides
[Non-text portions of this message have been removed]
Info: http://www.boost.org Wiki: http://www.crystalclearsoftware.com/cgi-bin/boost_wiki/wiki.pl Unsubscribe: mailto:boost-users-unsubscribe@yahoogroups.com
Your use of Yahoo! Groups is subject to http://docs.yahoo.com/info/terms/
Tanton Gibbs wrote:
Also, I was asked by a coworker if the following would be std C++:
BOOST_PP_LIST_FOR_EACH( DO_IT, BOOST_PP_EMPTY(), ARG_LIST )
I said that it would not because BOOST_PP_EMPTY would be expanded first to nothing, which would be the same as BOOST_PP_LIST_FOR_EACH( DO_IT, , ARG_LIST ) which Paul explicitly said below was non-conformant.
Is this correct?
Well, not exactly, but close. This, for example, is okay: #define EMPTY() #define MACRO(x) x MACRO( ) // undefined MACRO( EMPTY() ) // okay However, this is not: #define MACRO_2(x) MACRO(x) MACRO_2( EMPTY() ) // okay for MACRO_2, undefined for MACRO The reason is relatively simple. Before the argument is inserted into the replacement list of MACRO_2, it is macro expanded. In this case, it expands to nothing, which yields a replacement list like this: MACRO( ) Which is rescanned for macros to expand and consequently introduces undefined behavior. BOOST_PP_LIST_FOR_EACH, as well as virtually every other pp-lib primitive uses other macros, so it is never safe to do this: BOOST_PP_SOME_MACRO( BOOST_PP_EMPTY() ) C99 explicitly allows you to pass nothing as macro argument, but it is still undefined in C++. Regards, Paul Mensonides
This makes sense. So, replacement is done after substitution on the RHS,
not before macro argument substitution, correct?
In other words, with
#define EMPTY()
#define MACRO( x ) x
MACRO( EMPTY() )
would have EMPTY() substituted for the formal macro parameter x and the RHS
value x. Then, a macros are executed on the RHS changing EMPTY() into
nothing (literally).
----- Original Message -----
From: "Paul Mensonides"
Tanton Gibbs wrote:
Also, I was asked by a coworker if the following would be std C++:
BOOST_PP_LIST_FOR_EACH( DO_IT, BOOST_PP_EMPTY(), ARG_LIST )
I said that it would not because BOOST_PP_EMPTY would be expanded first to nothing, which would be the same as BOOST_PP_LIST_FOR_EACH( DO_IT, , ARG_LIST ) which Paul explicitly said below was non-conformant.
Is this correct?
Well, not exactly, but close. This, for example, is okay:
#define EMPTY() #define MACRO(x) x
MACRO( ) // undefined MACRO( EMPTY() ) // okay
However, this is not:
#define MACRO_2(x) MACRO(x)
MACRO_2( EMPTY() ) // okay for MACRO_2, undefined for MACRO
The reason is relatively simple. Before the argument is inserted into the replacement list of MACRO_2, it is macro expanded. In this case, it expands to nothing, which yields a replacement list like this:
MACRO( )
Which is rescanned for macros to expand and consequently introduces undefined behavior. BOOST_PP_LIST_FOR_EACH, as well as virtually every other pp-lib primitive uses other macros, so it is never safe to do this:
BOOST_PP_SOME_MACRO( BOOST_PP_EMPTY() )
C99 explicitly allows you to pass nothing as macro argument, but it is still undefined in C++.
Regards, Paul Mensonides
Info: http://www.boost.org Wiki: http://www.crystalclearsoftware.com/cgi-bin/boost_wiki/wiki.pl Unsubscribe: mailto:boost-users-unsubscribe@yahoogroups.com
Your use of Yahoo! Groups is subject to http://docs.yahoo.com/info/terms/
Tanton Gibbs wrote:
This makes sense. So, replacement is done after substitution on the RHS, not before macro argument substitution, correct?
In other words, with #define EMPTY() #define MACRO( x ) x
MACRO( EMPTY() ) would have EMPTY() substituted for the formal macro parameter x and the RHS value x. Then, a macros are executed on the RHS changing EMPTY() into nothing (literally).
No. Replacement and rescanning are done on each argument to a function-like macro before they are inserted into the replacement list (unless they are next to the token-pasting operator or the stringizing operator). However, this replacement and rescanning on the parameters happens *after* the arguments are delineated as "actual parameters." So, the replacement list is rescanned *after* the arguments have already been expanded. Take this example: #define X 1, 2 #define A(x) B(x) #define B(a, b) a + b A(X) // 1 + 2 This is perfectly legal and correct. The argument X is delineated as a single parameter to A. This single parameter is expanded and rescanned _prior_ to insertion into the replacement list of A. The expanded result of the parameter is inserted into the replacement list of A, yielding: B(1, 2) Then the replacement list of A is rescanned for more macros to replace--which causes B(1, 2) to be invoked. Note that some preprocessors do not do this expansion order correctly--notably VC++, so consider the above to be illustrative of what is *supposed* to happen. Make sense? Regards, Paul Mensonides
Yes, I think he just has a problem with using a placeholder value, he wants
to show, at the call site, that the value is not used.
----- Original Message -----
From: "Paul Mensonides"
Tanton Gibbs wrote:
Also, I was asked by a coworker if the following would be std C++:
[...]
BTW, are looking for a way to pass data as a macro argument sometimes and other times pass nothing?
Paul Mensonides
Info: http://www.boost.org Wiki: http://www.crystalclearsoftware.com/cgi-bin/boost_wiki/wiki.pl Unsubscribe: mailto:boost-users-unsubscribe@yahoogroups.com
Your use of Yahoo! Groups is subject to http://docs.yahoo.com/info/terms/
Tanton Gibbs wrote:
Yes, I think he just has a problem with using a placeholder value, he wants to show, at the call site, that the value is not used.
There are two ways to "simulate" passing nothing in C++. One is more intrusive at the point of call than the other: 1) BOOST_PP_EMPTY and BOOST_PP_IDENTITY: #define MACRO(x) x() MACRO( BOOST_PP_EMPTY ) // expands to nothing MACRO( BOOST_PP_IDENTITY( abc ) ) // expands to: abc 2) BOOST_PP_NIL and BOOST_PP_APPLY #define MACRO(x) BOOST_PP_APPLY(x) MACRO( BOOST_PP_NIL ) // expands to nothing MACRO( (abc) ) // expands to: abc Of course, these facilities are only necessary if you want to abstract the difference between "something" and "nothing." If he just wants to make it obvious that the parameter is not used, you can still use BOOST_PP_NIL (which is guaranteed to *not* be a macro) or pass "unused" or something similar. The only foolproof way is to pass a non-identifier token, such as an operator or a pp-number which cannot be used in any other context: MACRO( 0xIgnored ) Or a simple string literal: MACRO( "This parameter is ignored." ) Regards, Paul Mensonides
Eric Robert wrote:
Ok, I see that there are 3 ways of doing this now. What is the recommendation for something small like 2 or 3 lines for each native types i.e. more or less 12 iterations?
I'd use the local iteration facilities, in case you need to look at the preprocessor output for some reason. Otherwise, for something so small, take your pick. Regards, Paul Mensonides
participants (3)
-
Eric Robert
-
Paul Mensonides
-
Tanton Gibbs