C/C++ macro expanding to argument, argument as string
Asked Answered
M

4

9

I have many variables that are named the same as elements in an engineering specification document so the string version of the name is also useful.

I find myself using a macro like this a lot:

#define MACRO(a) a, #a

Typical usage is:

void someFunction(int a, const char *name);

someFunction(MACRO(meaningfully_named_variable));

My question is threefold:

  • Is there a better way of doing this?
  • Is a similar macro available in Boost or other libraries?
  • If not, how could I refine and rename this to make it clear and useful?

Edit I should have said that the above is a minimal example. The function might have other parameters and the named entity might be a data member or perhaps even a function itself.

Another extension I'm considering for C++ is a class NamedRef that could receive the contents of the macro.

template <typename T>
struct NamedRef
{
    NamedRef(T *t, const char *name) : t(t), name(name) { }
    T *t;
    const char *name;
};

template <typename T>
NamedRef<T> namedRef(T &t, const char *name)
{
    return NamedRef<T>(&t, name);
}

#define WITH_NAME(a) a, #a

// more sophisticated usage example
void otherFunction(double, NamedRef<int>, bool);

otherFunction(0.0, namedRef(object.WITH_NAME(meaningful_member_name)), false);
Mainis answered 21/12, 2011 at 23:13 Comment(2)
All I'd do is pick a more descriptive name for the macro, e.g. WITH_NAME().Lutanist
Do what @MarkRansom suggested. My answer was a long way of saying "it's fine" and that Boost has a macro called BOOST_STRINGIZE(X).Endorse
V
5

You could take it a step further:

#define SOMEFUNCTION(a) somefunction(a, #a)

However, this is only useful if you call the same function alot. Otherwise, I don't think there is any better way than your example. Of course, you should change the name of the macro to something more meaningful though, like ARGUMENTS or something.

Vocabulary answered 21/12, 2011 at 23:33 Comment(3)
True, but if I have a lot of functions that receive var, name then I will have to write a lot of macros.Mainis
Not necessarily => #define MACRO(funct_ptr, var) funct_ptr(var, #var) So you will need such many macro's how many different signature of function parameters you have...Silverside
OK, good thinking, but I think it's clearer to preserve the function syntax if possible, also function may have other args.Mainis
S
0
#define someFunction(a)  if (1) stringized_someFunction((a), #a ); else (void)0
void stringized_someFunction(int a, const char* name);

The if (1) stuff wraps up the macro so that it won't mess (usually) with loops, branches, if statements, etc.

You would then call your function like so:

int r = 4;
someFunction(r);

You only really add one extra line for each "function declaration." If the C preprocessor allowed multiple steps you could wrap it all up into one, but alas, it doesn't.

I forgot because I hope it's obvious that you'd need to write your function:

void stringized_someFunction(int a, const char* name)
{
  // Do stuff here
}

Anyhow it should be a lot easier and prettier to read that way.

Snatchy answered 22/12, 2011 at 0:6 Comment(4)
You forgot the semicolon in your macro definition before else. Also, I don`t think wrapping it in if(1) is necessary in this situation.Vocabulary
I know that you need to wrap multi-statement macros to prevent them from breaking code, but I don't understand the reason for single statements, if you could provide a counter-example it would be appreciated.Vocabulary
if (1) will cause problems if wrapped function needs to return a value.Mainis
It doesn't make sense to wrap a function call within an if(1) or do{}while(0); because you can't capture the result of the function call.Eggshell
H
0

You are likely to find that XMACROs are useful for this kind of work.

Handiwork answered 22/12, 2011 at 0:12 Comment(0)
R
0

As Jesse answered,

you can write like this:

void function1(int a, const char* name)
{
    cout << "a: " << a << endl;
    cout << "name: " << name << endl;
}

void function2(double d, const char* name, const char *str)
{
    cout << "d: " << d << endl;
    cout << "name: " << name << endl;
    cout << "str: " << str << endl;
}

#define MACRO(functionName, a) functionName(a, #a)
#define MACRO2(functionName, a, ...) functionName(a, #a, __VA_ARGS__)

int main()
{
    int a = 10;
    MACRO(function1, a);
    double d = 10.5;
    MACRO2(function2, d, "Hello world");
    return 0;
}

If you have more arguments to pass, you can use MACRO2 that uses variable arguments. You will have to pass the function name accordingly.

Roughen answered 22/12, 2011 at 9:18 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.