Boost logo

Boost Users :

Subject: Re: [Boost-users] [Preprocessor] MSVC nonstandard macro expansion workaround?
From: Edward Diener (eldiener_at_[hidden])
Date: 2016-03-04 18:57:19


On 3/3/2016 8:49 AM, rleigh_at_[hidden] wrote:
> Hi folks,
>
> I've been trying to get Boost.Preprocessor to run a nested for loop over
> two sequences to output nested switch blocks and case statements. This
> works fine with GCC and clang. Unfortunately it's broken with MSVC. If
> anyone had any thoughts on what I might need to tweak to enable the code
> to work with MSVC, I'd be very appreciative. Even if it's as nasty as a
> big ifdef with an alternative set of macros!
>
> This is the test case:
>
> --------
> #include <boost/preprocessor.hpp>
> #include <iostream>
>
> #define LASERTYPE_VALUES
> (EXCIMER)(GAS)(METALVAPOR)(SOLIDSTATE)(DYE)(SEMICONDUCTOR)(FREEELECTRON)(OTHER)
>
>
> enum LaserType
> {
> BOOST_PP_SEQ_ENUM(LASERTYPE_VALUES)
> };
>
> #define PP_SEQ_FOR_EACH_R_ID() BOOST_PP_SEQ_FOR_EACH_R
> #define PP_DEFER(x) x BOOST_PP_EMPTY()
>
> #define LT_NESTED(maR, maToplevelType, maNestedType) \
> std::cout << "Test nested: first=" << LaserType(maToplevelType) << "
> second=" << LaserType(maNestedType) << " \n";
>
> #define LT_TOPLEVEL(maR, maUnused, maType) \
> std::cout << "Test toplevel: " << LaserType(maType) << " \n"; \
> PP_DEFER(PP_SEQ_FOR_EACH_R_ID)()(maR, LT_NESTED, maType,
> LASERTYPE_VALUES);
>
> int main() {
> BOOST_PP_EXPAND(BOOST_PP_SEQ_FOR_EACH(LT_TOPLEVEL, %%,
> LASERTYPE_VALUES));
> }
> --------

You can simplify your efforts to avoid the
BOOST_PP_SEQ_FOR_EACH/BOOST_PP_SEQ_FOR_EACH_R nested recursion problem
by replacing:

#define LT_TOPLEVEL(maR, maUnused, maType) \
   std::cout << "Test toplevel: " << LaserType(maType) << " \n"; \
   PP_DEFER(PP_SEQ_FOR_EACH_R_ID)()(maR, LT_NESTED, maType,
LASERTYPE_VALUES);

with:

#define LT_TOPLEVEL(maR, maUnused, maType) \
   std::cout << "Test toplevel: " << LaserType(maType) << " \n"; \
   BOOST_PP_IDENTITY(BOOST_PP_SEQ_FOR_EACH_R)()(maR, LT_NESTED, maType,
LASERTYPE_VALUES);

and getting rid of the PP_SEQ_FOR_EACH_R_ID() and PP_DEFER(x) macros.

This will still work with gcc/clang but still fails with VC++. As I
mentioned in another message in this thread VC++ will often rescan after
macro replacement when it should not be doing so according to the C++
standard, and that is almost certainly what it is doing here to defeat
your efforts.

>
> On MSVC, I get this:
>
>> cl /EHsc /I \path\to\boost-1_60 /Fe:test-pp.exe test-pp.cpp
> Microsoft (R) C/C++ Optimizing Compiler Version 18.00.40629 for x64
> Copyright (C) Microsoft Corporation. All rights reserved.
>
> test-pp.cpp
> test-pp.cpp(22) : warning C4003: not enough actual parameters for macro
> 'BOOST_PP_VARIADIC_ELEM_3'
> test-pp.cpp(22) : warning C4003: not enough actual parameters for macro
> 'BOOST_PP_BOOL'
> test-pp.cpp(22) : warning C4003: not enough actual parameters for macro
> 'BOOST_PP_BOOL_I'
> test-pp.cpp(22) : warning C4003: not enough actual parameters for macro
> 'BOOST_PP_VARIADIC_ELEM_2'
> test-pp.cpp(22) : warning C4003: not enough actual parameters for macro
> 'BOOST_PP_DEC'
> test-pp.cpp(22) : warning C4003: not enough actual parameters for macro
> 'BOOST_PP_DEC_I'
> test-pp.cpp(22) : error C2065: 'BOOST_PP_SEQ_FOR_EACH_M' : undeclared
> identifier
> test-pp.cpp(22) : error C2065: 'BOOST_PP_TUPLE_EAT_2' : undeclared
> identifier
> test-pp.cpp(22) : error C2065: 'LT_NESTED' : undeclared identifier
> test-pp.cpp(22) : error C2064: term does not evaluate to a function
> taking 1 arguments
> test-pp.cpp(22) : error C2146: syntax error : missing ';' before
> identifier 'BOOST_PP_IIF_BOOST_PP_BOOL_'
> test-pp.cpp(22) : error C3861: 'BOOST_PP_IIF_BOOST_PP_BOOL_': identifier
> not found
> test-pp.cpp(22) : error C2065: 'BOOST_PP_FOR_3' : undeclared identifier
> test-pp.cpp(22) : error C2065: 'BOOST_PP_TUPLE_EAT_4' : undeclared
> identifier
> test-pp.cpp(22) : error C2059: syntax error : ','
> test-pp.cpp(22) : error C3861: 'BOOST_PP_EXPAND': identifier not found
> test-pp.cpp(22) : error C2065: 'BOOST_PP_FOR_4' : undeclared identifier
> test-pp.cpp(22) : error C2065: 'BOOST_PP_FOR_5' : undeclared identifier
> test-pp.cpp(22) : error C2065: 'BOOST_PP_FOR_6' : undeclared identifier
> test-pp.cpp(22) : error C2065: 'BOOST_PP_FOR_7' : undeclared identifier
> test-pp.cpp(22) : error C2065: 'BOOST_PP_FOR_8' : undeclared identifier
> test-pp.cpp(22) : error C2065: 'BOOST_PP_FOR_9' : undeclared identifier
> test-pp.cpp(22) : error C2065: 'BOOST_PP_FOR_10' : undeclared identifier
>
> I've spent hours tweaking the testcase to try to make this work, but so
> far without success. It doesn't help that I don't fully understand what
> specifically is broken with the MSVC preprocessor, or how to work around
> whatever is behaving in a non-stanadard way.


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net