简体   繁体   中英

Use type of variable declaration inside macro given named declaration

I've got a large C++20 codebase with a bunch of macro instantiations that are simple variations of this example:

void main() {
  MAKE_VAR(int myInt);
  MAKE_VAR(CMyClass myClass);
  MAKE_VAR(CMyClass *pMyClass);
};

Because the utility of the macro is part of a process that exists outside of the actual compilation of the code, the #define is currently trivial:

#define MAKE_VAR(var) var

Which means the resulting code after expansion is simply:

void main() {
  int myInt;
  CMyClass myClass;
  CMyClass *pMyClass;
};

But, I'm trying to add more smarts to MAKE_VAR that depends upon the type of the variable, and for compatibility reasons I'm unable to change that macro signature (eg having the macro take the type and name as separate arguments).

So, my question is whether or not there is some incantation whereby I can take the var macro argument and produce just the type of that argument for use as a template parameter in a subsequent bit of generated code. Note that I do not need to get the name out (nor do I believe that's possible with standard C++20).

That is, I would like to come up with a macro definition such that the above MyStruct example expands into something like this (with whatever extra boilerplate necessary):

void main() {
  int myInt;
  DoThing<int>();

  CMyClass myClass;
  DoThing<CMyClass>();

  CMyClass *pMyClass;
  DoThing<CMyClass *>();
};

My first attempts revolved around trying to get something I could pass into decltype , but I wasn't able to find any such incantation that permits the name being present.

I've gotten close to a solution with the following approach but I have a different problem, where it only works once (because FakeFunc doesn't have a unique name per instance - normally I would use something akin to __COUNTER__ or similar but I need it to work across both lines here):

template <typename Sig> struct ArgType;
template <typename Arg> struct ArgType<void(Arg)> { using type = Arg; };

#define MAKE_VAR(var) \
  var; \
  typedef void FakeFunc( var ); \
  DoThing<typename ArgType<FakeFunc>::type>();

void main() {
  MAKE_VAR(int myInt);
  MAKE_VAR(unsigned myUInt);
};

// Macro expands to:
void main() {
  int myInt;
  typedef void FakeFunc( int myInt );
  DoThing<typename ArgType<FakeFunc>::type>();

  unsigned myUInt;
  typedef void FakeFunc( unsigned myUInt );
  DoThing<typename ArgType<FakeFunc>::type>();
};

Any thoughts on finishing out this approach or using a different approach?

EDIT: Closing question for now because I need to clarify why I can't just put FakeFunc and DoThing in a local scope, which is a nuance I didn't capture in this simplified question...

You don't need to give a name to the function:

template <typename Sig> struct ArgType;
template <typename Arg> struct ArgType<void(*)(Arg)> { using type = Arg; };

template <typename T> void DoThing() {}

#define MAKE_VAR(var) \
  var; \
  DoThing<typename ArgType<void (*)( var )>::type>();

int main() {
        MAKE_VAR(int x)
        MAKE_VAR(unsigned y)
}

Live Demo

The macros expand to

int x; DoThing<typename ArgType<void (*)( int x )>::type>();
unsigned y; DoThing<typename ArgType<void (*)( unsigned y )>::type>();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM