[preprocessor] Argument list conversion
Hi, I have the following fun problem, seemingly simple, but couldn't find the trick. The objective is to convert a given argument list to some other one or more useful argument list. Each of the arguments are copied verbatim into the other list unless it is specified to be a SPECIAL_TYPE. For example the following two-argument macro function call: FUNKY_MACRO( 5, ( double*, SPECIAL_TYPE, const char[], SPECIAL_TYPE, int) ) would spit out: (double*, const char[], int, special1, special1); (double*, special1, const char[], special1, int, special2, special2); note that, in the first generated tuple SPECIAL_TYPE is replaced by some other text, and moved to the end of the tuple. In the second one, same replacement occurs and some yet other text is appended repeatedly at the end, same number of times as SPECIAL_TYPE appears in the original list. Any ideas how to do this (or part of it) with the incredibly amazing Preprocessor library? thanks -- Server Levent Yilmaz Mechanical Engineering University of Pittsburgh
On 6/15/07, Server Levent Yilmaz
Hi,
I have the following fun problem, seemingly simple, but couldn't find the trick.
The objective is to convert a given argument list to some other one or more useful argument list. Each of the arguments are copied verbatim into the other list unless it is specified to be a SPECIAL_TYPE.
For example the following two-argument macro function call:
FUNKY_MACRO( 5, ( double*, SPECIAL_TYPE, const char[], SPECIAL_TYPE, int) )
would spit out:
(double*, const char[], int, special1, special1); (double*, special1, const char[], special1, int, special2, special2);
note that, in the first generated tuple SPECIAL_TYPE is replaced by some other text, and moved to the end of the tuple. In the second one, same replacement occurs and some yet other text is appended repeatedly at the end, same number of times as SPECIAL_TYPE appears in the original list.
Any ideas how to do this (or part of it) with the incredibly amazing Preprocessor library?
thanks
--
I have a related, simpler question: Given a tuple (or any other container) with arbitrary elements, is there a way to determine if an element is SPECIAL_TEXT or some other text. For example given, ( a, b, SPECIAL_TEXT, c, d ), can we construct (0, 0, 1, 0, 0)? Levent
"Server Levent Yilmaz"
I have a related, simpler question:
Given a tuple (or any other container) with arbitrary elements, is there a way to determine if an element is SPECIAL_TEXT or some other text. For example given, ( a, b, SPECIAL_TEXT, c, d ), can we construct (0, 0, 1, 0, 0)?
If you know all the possibilities in advance, you can do something like: #define LOOKING_FOR_SPECIAL_TEXT 1 #define LOOKING_FOR_a 0 #define LOOKING_FOR_b 0 #define LOOKING_FOR_c 0 #define LOOKING_FOR_d 0 and then transform the sequence using concatination LOOKING_FOR_ with the current item. Regards, Arkadiy
On 6/15/07, Arkadiy Vertleyb
"Server Levent Yilmaz"
wrote I have a related, simpler question:
Given a tuple (or any other container) with arbitrary elements, is there a way to determine if an element is SPECIAL_TEXT or some other text. For example given, ( a, b, SPECIAL_TEXT, c, d ), can we construct (0, 0, 1, 0, 0)?
If you know all the possibilities in advance, you can do something like:
#define LOOKING_FOR_SPECIAL_TEXT 1 #define LOOKING_FOR_a 0 #define LOOKING_FOR_b 0 #define LOOKING_FOR_c 0 #define LOOKING_FOR_d 0
and then transform the sequence using concatination LOOKING_FOR_ with the current item.
Nope, I don't know in advance. In fact, those (a,b,...) are not really
single character text, but rather comma separated formal arguments to a
function such as (real *, const char[], etc... ), so concat wouldnt work
even if I knew the types a priori.
I did somehow come up with this dirty trick, though it doesn't quite cut it:
#include
Server Levent Yilmaz wrote:
I did somehow come up with this dirty trick, though it doesn't quite cut it:
<snip code>
any ideas?
Yep, here's another dirty trick ;-):
#include
On 6/16/07, Tobias Schwinger
Server Levent Yilmaz wrote:
I did somehow come up with this dirty trick, though it doesn't quite cut it:
<snip code>
any ideas?
Yep, here's another dirty trick ;-):
#include
#define SPECIAL (whatever) #define IS_SPECIAL BOOST_PP_IS_UNARY
IS_SPECIAL(a) // 0 IS_SPECIAL(b) // 0 IS_SPECIAL(SPECIAL) // 1
It isn't entirely portable to older preprocessors (that's why this code lives in preprocessor/detail) but should work with latest versions of the widely-used compilers.
That did it!! Thanks Tobias. FWIW, I have solved my original problem too. It is in fact not an entirely fun project, but became a helpful little library on its own, useful for mixed language programming (C++ calling Fortran, to be specific). The idea is the "stub code" outlined by Carsten A. Arnholm ( herehttp://arnholm.org/software/cppf77/cppf77.htm#Section4) Arnholm generates the stub code with an external script. I managed to do it with preprocessor only. So, the library effectively converts the following: FORTRAN_FUNCTION (int, foo, FOO, 3, (CHAR, double*, int&) ); FORTRAN_SUBROUTINE ( bar, BAR, 4, (CHAR, const double&, CHAR, int*) ); into, #ifdef F77_STUB_REQUIRED extern "C" void bar_ (const char*, const double&, const char*, int*, size_t, size_t); inline void BAR ( internal_character_type v0, double* v1, internal_character_type v2, int& v3 ) { bar_(v0.p, v1, v2.p, v3, v0.n, v2.n); } #else // in MS compilers extern "C" int __stdcall FOO( const char*, size_t, double*, int&); extern "C" void __stdcall BAR( internal_character_type, const double&, internal_character_type, int*); #endif The library code is in the vault (fortran.h herehttp://boost-consulting.com/vault/index.php?direction=0&order=&directory=Preprocessor%2520Metaprogramming&) in case anyone is interested. regards, Levent -- Server Levent Yilmaz Mechanical Engineering University of Pittsburgh
Tobias Schwinger
Yep, here's another dirty trick :
#include
#define SPECIAL (whatever) #define IS_SPECIAL BOOST_PP_IS_UNARY
IS_SPECIAL(a) // 0 IS_SPECIAL(b) // 0 IS_SPECIAL(SPECIAL) // 1
It isn't entirely portable to older preprocessors (that's why this code lives in preprocessor/detail) but should work with latest versions of the widely-used compilers.
This also works:
#include
Roman Perepelitsa wrote:
Tobias Schwinger
writes: Yep, here's another dirty trick :
#include
#define SPECIAL (whatever) #define IS_SPECIAL BOOST_PP_IS_UNARY
IS_SPECIAL(a) // 0 IS_SPECIAL(b) // 0 IS_SPECIAL(SPECIAL) // 1
It isn't entirely portable to older preprocessors (that's why this code lives in preprocessor/detail) but should work with latest versions of the widely-used compilers.
This also works:
#include
#include #define SPECIAL #define IS_SPECIAL(x) BOOST_PP_IS_EMPTY(BOOST_PP_EMPTY() x)
Yep, that's even better as it allows x to be anything. Got some idea how portable it is? Regards, Tobias
Tobias Schwinger
This also works:
#include
#include #define SPECIAL #define IS_SPECIAL(x) BOOST_PP_IS_EMPTY(BOOST_PP_EMPTY() x)
Yep, that's even better as it allows x to be anything. Got some idea how portable it is?
I'm not a preprocessor guru, but it works for msvc 8.0 and gcc 3.4. Roman Perepelitsa
On 6/18/07, Tobias Schwinger
Roman Perepelitsa wrote:
Tobias Schwinger
writes: Yep, here's another dirty trick :
#include
#define SPECIAL (whatever) #define IS_SPECIAL BOOST_PP_IS_UNARY
IS_SPECIAL(a) // 0 IS_SPECIAL(b) // 0 IS_SPECIAL(SPECIAL) // 1
It isn't entirely portable to older preprocessors (that's why this code lives in preprocessor/detail) but should work with latest versions of the widely-used compilers.
This also works:
#include
#include #define SPECIAL #define IS_SPECIAL(x) BOOST_PP_IS_EMPTY(BOOST_PP_EMPTY() x)
Yep, that's even better as it allows x to be anything. Got some idea how portable it is?
Well, IS_UNARY trick also works for pretty much anything except maybe another non-SPECIAL unary. What exactly is the offending code in BOOST_PP_IS_UNARY that makes it non-portable? -- Server Levent Yilmaz Mechanical Engineering University of Pittsburgh
Server Levent Yilmaz wrote:
On 6/18/07, *Tobias Schwinger*
mailto:tschwinger@isonews2.com> wrote: Roman Perepelitsa wrote: > Tobias Schwinger
http://isonews2.com> writes: > >> Yep, here's another dirty trick : >> >> #include >> >> #define SPECIAL (whatever) >> #define IS_SPECIAL BOOST_PP_IS_UNARY >> >> IS_SPECIAL(a) // 0 >> IS_SPECIAL(b) // 0 >> IS_SPECIAL(SPECIAL) // 1 >> >> It isn't entirely portable to older preprocessors (that's why this code >> lives in preprocessor/detail) but should work with latest versions of >> the widely-used compilers. > > This also works: > > #include > #include > > #define SPECIAL > #define IS_SPECIAL(x) BOOST_PP_IS_EMPTY(BOOST_PP_EMPTY() x) > Yep, that's even better as it allows x to be anything. Got some idea how portable it is?
Well, IS_UNARY trick also works for pretty much anything except maybe another non-SPECIAL unary.
Or a non-SPECIAL non-unary tuple, e.g. (foo,bar).
What exactly is the offending code in BOOST_PP_IS_UNARY that makes it non-portable?
IIRC, there is no offending code - just some deficient preprocessor implementations around that can't handle it... Regards, Tobias
On 6/18/07, Roman Perepelitsa
Tobias Schwinger
writes: Yep, here's another dirty trick :
#include
#define SPECIAL (whatever) #define IS_SPECIAL BOOST_PP_IS_UNARY
IS_SPECIAL(a) // 0 IS_SPECIAL(b) // 0 IS_SPECIAL(SPECIAL) // 1
It isn't entirely portable to older preprocessors (that's why this code lives in preprocessor/detail) but should work with latest versions of the widely-used compilers.
This also works:
#include
#include #define SPECIAL #define IS_SPECIAL(x) BOOST_PP_IS_EMPTY(BOOST_PP_EMPTY() x)
This is great. I am really surprised that it works in a comma separated argument list, and that you can pass around a funny array (4, (a1, a2, , a3) ), and work on it as expected. There is very slight usage problem though. An input such as ( int, double&, , char* ) where the second comma is a typo, is a valid expression and produces a syntactically correct prototype (see my previous post where I am using this IS_SPECIAL macro), and goes unnoticed, until crashing miserably in run time! L. -- Server Levent Yilmaz Mechanical Engineering University of Pittsburgh
Server Levent Yilmaz wrote:
On 6/18/07, *Roman Perepelitsa*
mailto:roman.perepelitsa@db.com> wrote: Tobias Schwinger
http://isonews2.com> writes: > Yep, here's another dirty trick : > > #include
> > #define SPECIAL (whatever) > #define IS_SPECIAL BOOST_PP_IS_UNARY > > IS_SPECIAL(a) // 0 > IS_SPECIAL(b) // 0 > IS_SPECIAL(SPECIAL) // 1 > > It isn't entirely portable to older preprocessors (that's why this code > lives in preprocessor/detail) but should work with latest versions of > the widely-used compilers. This also works:
#include
#include #define SPECIAL #define IS_SPECIAL(x) BOOST_PP_IS_EMPTY(BOOST_PP_EMPTY() x)
This is great. I am really surprised that it works in a comma separated argument list, and that you can pass around a funny array (4, (a1, a2, , a3) ), and work on it as expected.
This behavior, however, is not backed by the current standard! That's why Roman added BOOST_PP_EMPTY(), I guess, so the argument itself isn't empty and expands to emptiness during expansion of the invoked macro. Regards, Tobias
On 6/18/07, Tobias Schwinger
Server Levent Yilmaz wrote:
On 6/18/07, *Roman Perepelitsa*
mailto:roman.perepelitsa@db.com> wrote: Tobias Schwinger
http://isonews2.com> writes: > Yep, here's another dirty trick : > > #include
> > #define SPECIAL (whatever) > #define IS_SPECIAL BOOST_PP_IS_UNARY > > IS_SPECIAL(a) // 0 > IS_SPECIAL(b) // 0 > IS_SPECIAL(SPECIAL) // 1 > > It isn't entirely portable to older preprocessors (that's why this code > lives in preprocessor/detail) but should work with latest versions of
> the widely-used compilers.
This also works:
#include
#include #define SPECIAL #define IS_SPECIAL(x) BOOST_PP_IS_EMPTY(BOOST_PP_EMPTY() x)
This is great. I am really surprised that it works in a comma separated argument list, and that you can pass around a funny array (4, (a1, a2, , a3) ), and work on it as expected.
This behavior, however, is not backed by the current standard!
That's why Roman added BOOST_PP_EMPTY(), I guess, so the argument itself isn't empty and expands to emptiness during expansion of the invoked macro.
Take a look at this: #define SPECIAL #define IS_SPECIAL(x) BOOST_PP_IS_EMPTY(BOOST_PP_EMPTY() x) #define MACRO(i,z,array) IS_SPECIAL( BOOST_PP_ARRAY_ELEM(i, array) ) #define ENUM( n, tuple ) BOOST_PP_ENUM( n, MACRO, (n, tuple) ) ENUM( 3, ( arg1, , arg3) ) //1 ENUM( 3, ( arg1, SPECIAL, arg3) ) //2 In this context, can we safely say that 2 complies with standards more than 1? cheers, L. -- Server Levent Yilmaz Mechanical Engineering University of Pittsburgh
Take a look at this: #define SPECIAL #define IS_SPECIAL(x) BOOST_PP_IS_EMPTY(BOOST_PP_EMPTY() x)#define MACRO (i,z,array) IS_SPECIAL( BOOST_PP_ARRAY_ELEM(i, array) ) #define ENUM( n, tuple ) BOOST_PP_ENUM( n, MACRO, (n, tuple) )ENUM( 3, ( arg1, , arg3) ) //1 ENUM( 3, ( arg1, SPECIAL, arg3) ) //2 In this context, can we safely say that 2 complies with standards more than 1?cheers, L.
Both should be rejected by C++ standard conformant compiler. Although all compilers I'm aware of successfully compile this code (some of them produce warning). Here are examples of empty macro arguments processing. Example 1: #define A(x) #define B A(B) // ok Example 2: #define A1(x) #define A(x) A1(x) #define B A(B) // error because of double expansion Both examples are standard conforming for C99 preprocessor and C++0x preprocessor. Although second example is not standard conforming for C++03 preprocessor. Roman Perepelitsa.
Server Levent Yilmaz wrote:
Take a look at this:
#define SPECIAL #define IS_SPECIAL(x) BOOST_PP_IS_EMPTY(BOOST_PP_EMPTY() x)
#define MACRO(i,z,array) IS_SPECIAL( BOOST_PP_ARRAY_ELEM(i, array) ) #define ENUM( n, tuple ) BOOST_PP_ENUM( n, MACRO, (n, tuple) )
ENUM( 3, ( arg1, , arg3) ) //1 ENUM( 3, ( arg1, SPECIAL, arg3) ) //2
In this context, can we safely say that 2 complies with standards more than 1?
No, because the argument to IS_SPECIAL (within MACRO) might expand to emptiness, anyway. #define MACRO(z,i,array) BOOST_PP_IS_EMPTY(BOOST_PP_EMPTY() \ BOOST_PP_ARRAY_ELEM(i,array) ) Is better, though still not correct: SPECIAL within 'array' expands to nothing before 'array' is passed to PP_ARRAY_ELEM. Now the problem occurs within the PP library. Now we'd have to know the exact number of expansions to defer the expansion of SPECIAL so many times that the final expansion to emptiness happens just within PP_IS_EMPTY: #define E() // Empty #define X(x) x // eXpand // demonstrate expansion gets deferred E E E E()()()() // E E E ()()() X( E E E E()()()() ) // E E () X(X( E E E E()()()() )) // E () X(X(X( E E E E()()()() ))) // #define SPECIAL E E E E E E E E E E E E E E E E E E E E E \ ()()()()()()()()()()()()()()()()()()()()() //#define MACRO(z,i,array) \ // BOOST_PP_IS_EMPTY( BOOST_PP_ARRAY_ELEM(i, array) ) #define MACRO(z,i,array) BOOST_PP_ARRAY_ELEM(i, array) #define ENUM( n, tuple ) BOOST_PP_ENUM( n, MACRO, (n, tuple) ) ENUM(3, (arg1, SPECIAL, arg3)) // arg1 , E () , arg3 This code works as expected with the GNU preprocessor. You can't rely on the number of expansions to be the same for another PP, since Boost.PP might have to correct PP misbehavior, taking a different "control path", for things to work at all. It's quite easy to cross the line messing with emptiness #define FOO(x) _ ## x #define BAR(x) FOO(x) FOO(BOOST_PP_EMPTY()) // OK, expands to _BOOST_PP_EMPTY() BAR(BOOST_PP_EMPTY()) // -undefined behavior- so ideally one finds a way not to have to mess with it at all, e.g: #define SAFE(optional) optional() #define STILL_SAFE(optional) SAFE(optional) SAFE(BOOST_PP_EMPTY) // expands to nothing SAFE(BOOST_PP_IDENTITY(xyz)) // xyz STILL_SAFE(BOOST_PP_EMPTY) // expands to nothing Regards, Tobias
participants (4)
-
Arkadiy Vertleyb
-
Roman Perepelitsa
-
Server Levent Yilmaz
-
Tobias Schwinger