[preprocessor] How to prevent macro expansion with SEQ?

Hello, I have the following macro code: #define PY_DEFINE_CONSTANT(X) scope().attr(#X) = X #define PY_DEFINE_CONSTANTS_HELPER(R, DATA, X) PY_DEFINE_CONSTANT(X); #define PY_DEFINE_CONSTANTS(SEQ) \ BOOST_PP_SEQ_FOR_EACH(PY_DEFINE_CONSTANTS_HELPER, BOOST_PP_EMPTY, SEQ) This works fine when used with non-macro arguments: PY_DEFINE_CONSTANTS((foo)(bar)) expands to: scope().attr("foo") = foo; scope().attr("bar") = bar; But when foo and bar are macros like this: #define foo 1 #define bar 2 it expands to: scope().attr("1") = 1; scope().attr("2") = 2; Is there a way to get this: scope().attr("foo") = 1; scope().attr("bar") = 2; or this: scope().attr("foo") = foo; scope().attr("bar") = bar; IOW, how can I prevent macro expansion for X when invoked from PY_DEFINE_CONSTANTS()? TIA, Markus

-----Original Message----- From: boost-bounces@lists.boost.org [mailto:boost-bounces@lists.boost.org] On Behalf Of Markus Schöpflin
Is there a way to get this:
scope().attr("foo") = 1; scope().attr("bar") = 2;
or this:
scope().attr("foo") = foo; scope().attr("bar") = bar;
IOW, how can I prevent macro expansion for X when invoked from PY_DEFINE_CONSTANTS()?
The only way to prevent expansion is with # and ##--and that's all about timing. #include <boost/preprocessor/cat.hpp> #include <boost/preprocessor/facilities/intercept.hpp> #include <boost/preprocessor/seq/for_each.hpp> #include <boost/preprocessor/tuple/elem.hpp> #define PY_DEFINE_CONSTANTS_NO_EXPANSION_HELPER(r, data, x) \ scope().attr(BOOST_PP_TUPLE_ELEM(2, 0, x)) = BOOST_PP_TUPLE_ELEM(2, 1, x); \ /**/ #define PY_DEFINE_CONSTANTS_NO_EXPANSION(seq) \ BOOST_PP_SEQ_FOR_EACH( \ PY_DEFINE_CONSTANTS_NO_EXPANSION_HELPER, ~, \ BOOST_PP_CAT(PY_DEFINE_CONSTANTS_NO_EXPANSION_A seq ## 0, 0) \ ) \ /**/ #define PY_DEFINE_CONSTANTS_NO_EXPANSION_A(x) ((#x, x)) PY_DEFINE_CONSTANTS_NO_EXPANSION_B #define PY_DEFINE_CONSTANTS_NO_EXPANSION_B(x) ((#x, x)) PY_DEFINE_CONSTANTS_NO_EXPANSION_A #define PY_DEFINE_CONSTANTS_NO_EXPANSION_A0 #define PY_DEFINE_CONSTANTS_NO_EXPANSION_B0 #define foo 1 #define bar 2 PY_DEFINE_CONSTANTS_NO_EXPANSION((foo)(bar) BOOST_PP_INTERCEPT_) The trick here is to get the sequence inside the machinery in a way that allows the machinery to prevent it from expanding. That's the trailing 'INTERCEPT_ and the 'seq ## 0'. From there, it can be immediately processed with custom sequential iteration to make a new sequence with a argument/string pairs. This is about the best way that you can do it, but I won't guarantee that it will work on buggy preprocessors. In fact, I know it won't work on VC. The timing is tricky, and it's intrusive on the interface, but that's about the only way that it can be done. Regards, Paul Mensonides

Paul Mensonides wrote:
-----Original Message----- From: boost-bounces@lists.boost.org [mailto:boost-bounces@lists.boost.org] On Behalf Of Markus Schöpflin
Is there a way to get this:
scope().attr("foo") = 1; scope().attr("bar") = 2;
or this:
scope().attr("foo") = foo; scope().attr("bar") = bar;
IOW, how can I prevent macro expansion for X when invoked from PY_DEFINE_CONSTANTS()?
The only way to prevent expansion is with # and ##--and that's all about timing.
[snip solution]
The trick here is to get the sequence inside the machinery in a way that allows the machinery to prevent it from expanding. That's the trailing 'INTERCEPT_ and the 'seq ## 0'. From there, it can be immediately processed with custom sequential iteration to make a new sequence with a argument/string pairs.
I see and I'm amazed, as usual when dealing with the preprocessor. :-)
This is about the best way that you can do it, but I won't guarantee that it will work on buggy preprocessors. In fact, I know it won't work on VC. The timing is tricky, and it's intrusive on the interface, but that's about the only way that it can be done.
Fortunately I don't have to use MSVC, but you are right, the interface doesn't really look nice. I think I'll have to make a little poll at the office on what's better: PY_DEFINE_CONSTANT(foo); PY_DEFINE_CONSTANT(bar); or PY_DEFINE_CONSTANTS((foo)(bar) BOOST_PP_INTERCEPT_) Maybe we'll just stick with the simple macro then. Thanks for your help! Markus

-----Original Message----- From: boost-bounces@lists.boost.org [mailto:boost-bounces@lists.boost.org] On Behalf Of Markus Schöpflin
I see and I'm amazed, as usual when dealing with the preprocessor. :-)
Note, BTW, if arbitrary token-pasting of any two preprocessing tokens was well-defined, you could do it without the interface intrusion. With C99's placemarkers, you can do it with minimal intrusion: PY_DEFINE_CONSTANTS((foo)(bar),)
This is about the best way that you can do it, but I won't guarantee that it will work on buggy preprocessors. In fact, I know it won't work on VC. The timing is tricky, and it's intrusive on the interface, but that's about the only way that it can be done.
Fortunately I don't have to use MSVC, but you are right, the interface doesn't really look nice. I think I'll have to make a little poll at the office on what's better:
PY_DEFINE_CONSTANT(foo); PY_DEFINE_CONSTANT(bar);
or
PY_DEFINE_CONSTANTS((foo)(bar) BOOST_PP_INTERCEPT_)
Maybe we'll just stick with the simple macro then.
You don't have to use BOOST_PP_INTERCEPT_. You just need something that 1) expands to nothing when a specific thing is pasted to it and 2) doesn't defer macro expansion. For the latter, it means that it can't be concatenated to the left side of 'seq'. E.g. it could be as simple as: #define PY_DEFINE_CONSTANTS(seq) \ ... seq ## 0xPY_DEFINE_CONSTANTS_UNDERSCORE ... \ /**/ #define _0xPY_DEFINE_CONSTANTS_UNDERSCORE PY_DEFINE_CONSTANTS((foo)(bar)_) Regards, Paul Mensonides

"Paul Mensonides" <pmenso57@comcast.net> writes:
PY_DEFINE_CONSTANTS_NO_EXPANSION((foo)(bar) BOOST_PP_INTERCEPT_)
The trick here is to get the sequence inside the machinery in a way that allows the machinery to prevent it from expanding. That's the trailing 'INTERCEPT_ and the 'seq ## 0'. From there, it can be immediately processed with custom sequential iteration to make a new sequence with a argument/string pairs.
According to http://www.boost.org/libs/preprocessor/doc/ref/intercept.html there's no trailing underscore. Am I missing something? -- Dave Abrahams Boost Consulting www.boost-consulting.com

-----Original Message----- From: boost-bounces@lists.boost.org [mailto:boost-bounces@lists.boost.org] On Behalf Of David Abrahams
PY_DEFINE_CONSTANTS_NO_EXPANSION((foo)(bar) BOOST_PP_INTERCEPT_)
The trick here is to get the sequence inside the machinery in a way that allows the machinery to prevent it from expanding. That's the trailing 'INTERCEPT_ and the 'seq ## 0'. From there, it can be immediately processed with custom sequential iteration to make a new sequence with a argument/string pairs.
According to http://www.boost.org/libs/preprocessor/doc/ref/intercept.html there's no trailing underscore. Am I missing something?
I'm cheating a bit. INTERCEPT expands to INTERCEPT_, which expands to nothing when a number is pasted to the tail. In this context, INTERCEPT won't expand in time, so you'd get INTERCEPT0, which won't expand at all (because it isn't a macro), rather than INTERCEPT_0 (which will). The library is not designed to allow for the sort of timing required for delayed invocation. Rather, it is intentionally designed (in most cases) to allow arguments to expand on input. Plus, not only is it impossible to do portably, it can quickly become a vertical dependency nightmare because macros start expanding in contexts that they weren't designed to expand in. I.e. the implementation details of macros, in particular, become subject to the environment context (i.e. what macros are currently disabled). Chaos has limited support for this type of thing, but it really is limited. What you can do in these contexts becomes severally restricted with respect to what other library primitives you can use. One thing that you can do safely, relative to expansion timing, is delay invocation all the way through some other macro (several ways to do this). But it is dangerous to make something expand some arbitrary number of steps into another macro expansion. Regards, Paul Mensonides
participants (3)
-
David Abrahams
-
Markus Schöpflin
-
Paul Mensonides