Opened 14 years ago

Closed 14 years ago

#2329 closed Bugs (invalid)

GCC preprocessing error

Reported by: rtelyuk@… Owned by: No-Maintainer
Milestone: Boost 1.37.0 Component: preprocessor
Version: Boost 1.36.0 Severity: Problem
Keywords: Cc:

Description

#include "boost/preprocessor.hpp"

#define _NOP() #define _UL() _ #define _SC() ; #define CLASS( name ) class name #define STRUCT( name ) struct name

#define _PUBLIC() public #define _PRIVATE() private #define _PROTECTED() protected

#define DECLARE_MEMBER(r, d, mem) \

BOOST_PP_TUPLE_ELEM(2, 0, mem) BOOST_PP_TUPLE_ELEM(2, 1, mem) _SC()

#define DECLARE_ARG_CONSTRUCT(r, d, arg) \

BOOST_PP_TUPLE_ELEM(2, 0, arg) BOOST_PP_TUPLE_ELEM(2, 1, arg)_UL() BOOST_PP_EXPR_IF(BOOST_PP_LESS_EQUAL(r,d), BOOST_PP_COMMA())

#define DECLARE_ARG_CONSTRUCT_INIT(r, d, arg) \

BOOST_PP_TUPLE_ELEM(2, 1, arg) ( BOOST_PP_TUPLE_ELEM(2, 1, arg)_UL() ) BOOST_PP_EXPR_IF(BOOST_PP_LESS_EQUAL(r,d), BOOST_PP_COMMA())

#define DECLARE_T( lang_type, name, memeber_seq, member_access ) \

lang_type(name) { \ name ( \ BOOST_PP_SEQ_FOR_EACH( DECLARE_ARG_CONSTRUCT, BOOST_PP_SEQ_SIZE(memeber_seq), memeber_seq ) \ ) : \ BOOST_PP_SEQ_FOR_EACH( DECLARE_ARG_CONSTRUCT_INIT, BOOST_PP_SEQ_SIZE(memeber_seq), memeber_seq ) \ {} \ member_access##: \ BOOST_PP_SEQ_FOR_EACH( DECLARE_MEMBER , _NOP(), memeber_seq) \ };

#define DEF_TN( t,n ) ((t,n))

Use in code: DECLARE_T( STRUCT, some, DEF_TN(int, a) DEF_TN(int, b) DEF_TN(int, c), _PUBLIC() )

Two compilers MSVC++ 2005 for Win platform and XCode 3.0 GCC for MacOSX platform

Result: MSVC++ 2005 /W4 ― preprocessing succeful: struct some { some ( int a_ , int b_ , int c_ ) : a ( a_ ) , b ( b_ ) , c ( c_ ) {} public: int a ; int b ; int c ; };

XCode GCC ― error: macro "BOOST_PP_EXPR_IIF" passed 3 arguments, but takes just 2

Change History (1)

comment:1 by Daniel James, 14 years ago

Resolution: invalid
Status: newclosed

Hi, this isn't a preprocessor bug, it's because of differences in the preprocessor implementations. The Visual C++ preprocessor doesn't follow the standard very closely, so without some care anything developed with it could easily not be portable.

This really is something that should be sent to boost users, but I'll give you a few hints. First the problem you described is caused by your use of BOOST_PP_COMMA. It's getting expanded much earlier of gcc, and treated as a parameter seperator. A better way to do this would be something like:

#define DECLARE_ARG_CONSTRUCT_INIT(r, d, arg) \
    BOOST_PP_TUPLE_ELEM(2, 1, arg) ( BOOST_PP_CAT(BOOST_PP_TUPLE_ELEM(2, 1, arg), _UL()) )

#define DECLARE_T ... \
BOOST_PP_SEQ_ENUM(BOOST_PP_SEQ_TRANSFORM( \
  DECLARE_ARG_CONSTRUCT_INIT, BOOST_PP_SEQ_SIZE(memeber_seq), memeber_seq)) \
  ...

You'll notice I used BOOST_PP_CAT to concatenate the underscore. This is because you're relying on a bug in Visual C++ which concatenates the results of functions with the following token. So instead of:

BOOST_PP_TUPLE_ELEM(2, 1, arg)_UL() 

use:

BOOST_PP_CAT(BOOST_PP_TUPLE_ELEM(2, 1, arg), _UL())

You've got a lot of pointless macros, such as _PRIVATE, _PUBLIC, _PROTECTED, _NOP and _UL. You can just use the keyword or symbol. Also names that start with an underscore and a capital are reserved, so you shouldn't use them. The code above becomes:

BOOST_PP_CAT(BOOST_PP_TUPLE_ELEM(2, 1, arg), _)

You're also going to run into trouble with member_access##: because you can only concatenate with numbers and identifiers (i.e. [0-9A-Za-z_]). member_access : should be fine - no concatenation is required.

Note: See TracTickets for help on using tickets.