4

There are some cases where you need to (a) have a macro which (b) parenthesizes one of its arguments in (c) a case where the language does not allow parentheses.

Simple example:

#define MAKE_STRUCT(name, base) struct name : base { }

struct X { };
MAKE_STRUCT(Y, X);   // ok
MAKE_STRUCT(Z, (X)); // error

This is an error because we're expecting a type name and we get (. ecatmur provides a clever workaround for this by taking advantage of the fact that there are other parts of the language that do allow for an extra set of parentheses:

template<typename T> struct argument_type;
template<typename T, typename U> struct argument_type<T(U)> { typedef U type; };

#define MAKE_STRUCT(name, base) struct name : argument_type<void(base)>::type { }

struct X { };
MAKE_STRUCT(Y, X);   // ok
MAKE_STRUCT(Z, (X)); // ok

This compiles on gcc and clang, but it does not compile on MSVC. Is there either an MSVC-specific trick to allow for parentheses or a different trick that works on all three compilers?

This possibly-parenthesized type is passed through several macros - so I'm not sure that the other answers could apply (the context here is trying to pass multiple template parameters to a fixture using Catch2's TEST_CASE_METHOD()).

Barry
  • 286,269
  • 29
  • 621
  • 977

2 Answers2

4

So I came to the following pure-preprocessor solution that will strip parentheses only when they are present. Seems to work in vc++, g++ and clang++ and probably can be modified to deal with several levels of parentheses.

#define MAKE_STRUCT(name, base) struct name: EXPAND1(DEF base) {}
#define EXPAND1(param) EXPAND2(param)
#define EXPAND2(param) NO## param
#define DEF(param) DEF param
#define NODEF

struct X { };
MAKE_STRUCT(Y, X);   // ok
MAKE_STRUCT(Z, (X)); // ok

online compiler

user7860670
  • 35,849
  • 4
  • 58
  • 84
  • In my case the `X` really has a comma in it, but that's a trivial change to make `DEF` and `EXPAND2` take `...` instead. Wonderful, thank you. The preprocessor is still basically magic to me. – Barry Apr 20 '18 at 03:55
-1

Not the great solution, but if structs in question can be tinkered with, and only ONE level of parenthesis is to be supported, this seems to work:

struct tag {};

#define MAKE_STRUCT(name, base) struct name : \
  decltype(base(tag{})) { };

struct X {
     X(tag );
     X() = default;
};

MAKE_STRUCT(Y, X);   // ok
MAKE_STRUCT(Z, (X)); // ok
SergeyA
  • 61,605
  • 5
  • 78
  • 137