Why is the nested macro not unfolded? - c++

I am using nested macro under gcc-9.3.1.
Here is the code.
#define A(_name) _name, _name, _name
#define P(_1, _2, _name, ...) _name
#define B(...) P(__VA_ARGS__, A(something))(__VA_ARGS__)
B(k)
I expected the B(k) converted to P(k, something, something, something)(k) at first and then converted into something(k).
However, compilier told me that two arguments were too few for P, which meant that A(something) was not unfolded.
Why is that? And how can I make it unfolded?

B(k) expands to P(k, A(something))(k) which then undergoes recursive expansion. The first thing it finds there is P, which doesn't have enough arguments.
If you want this to work the way I think you do, you need to arrange for A to expand before P. You can do that by adding explicit indirect EXPAND macros:
#define EXPAND(...) __VA_ARGS__
#define B(...) EXPAND(P EXPAND((__VA_ARGS__, A(something))))(__VA_ARGS__)
This way, P won't be recognized as a macro (no following () until after the inner EXPAND is expanded (which will also expand A). You need the outer EXPAND to explicitly expand P afterwards.

Related

Is there anyway to use for loop with string macro?

I have the following defines:
#define STRING_OBJECT_1 "bird"
#define STRING_OBJECT_2 "dog"
#define STRING_OBJECT_3 "cat"
#define STRING_OBJECT_4 "human"
#define STRING_OBJECT_5 "cow"
#define STRING_OBJECT_6 "snake"
#define STRING_OBJECT_7 "penguin"
#define STRING_OBJECT_8 "monkey"
I want to get numbered STRING_OBJECT only using STRING_OBJECT_ + "(number string)", so basically not directly type STRING_OBJECT_1.
Is there anyway to use for loop with string macro in C++?
Is there anyway to use for loop with string macro in C++?
No, there isn't.
Macros are processed before source code is compiled to create object code.
The values of variables in a for loop are set at run time. Hence, they cannot make use of macros.
Your best bet is to augment your code with an array variable and use the array variable in the for loop.
#define STRING_OBJECT_1 "bird"
...
#define STRING_OBJECT_8 "monkey"
std::string object_array[] = {STRING_OBJECT_1, ..., STRING_OBJECT_8};
for ( int i = 0; ... )
{
do_something(object_array[i]);
}
No, You can't do this. macros not part of the C/C++ language.
Macros are replaced by the preprocessor by their value compiles time. There is no way you had be able to change the macro at runtime.

c++ macro recognizing tokens as arguments

So, it's been a while since I have written anything in C++ and now I'm working on a project using C++11 and macros.
I know that by using the stringify operator I can do this:
#define TEXT(a) #a //expands to "a"
How am I supposed to use the preprocessor for recognizing the tokens like + and * to do this:
#define TEXT(a)+ ??? //want to expand to "a+"
#define TEXT(a)* ??? //want to expand to "a*"
when the input has to be in that syntax?
I have tried doing that:
#define + "+"
but of course it doesn't work. How can I make the preprocessor recognize those tokens?
NOTE:
This is actually part of a project for a small language that defines and uses regular expressions, where the resulting string of the macros is to be used in a regex. The syntax is given and we have to use it as it is without making any changes to it.
eg
TEXT(a)+ is to be used to make the regular expression: std::regex("a+")
without changing the fact that TEXT(a) expands to "a"
First,
#define TEXT(a) #a
doesn't “convert to "a"”. a is just a name for a parameter. The macro expands to a string that contains whatever TEXT was called with. So TEXT(42 + rand()) will expand to "42 + rand()". Note that, if you pass a macro as parameter, the macro will not be expanded. TEXT(EXIT_SUCCESS) will expand to "EXIT_SUCCESS", not "0". If you want full expansion, add an additional layer of indirection and pass the argument to TEXT to another macro TEXT_R that does the stringification.
#define TEXT_R(STUFF) # STUFF
#define TEXT(STUFF) TEXT_R(STUFF)
Second, I'm not quite sure what you mean with TEXT(a)+ and TEXT(a)*. Do you want, say, TEXT(foo) to expand to "foo+"? I think the simplest solution in this case would be to use the implicit string literal concatenation.
#define TEXT_PLUS(STUFF) # STUFF "+"
#define TEXT_STAR(STUFF) # STUFF "*"
Or, if you want full expansion.
#define TEXT_R(STUFF) # STUFF
#define TEXT_PLUS(STUFF) TEXT_R(STUFF+)
#define TEXT_STAR(STUFF) TEXT_R(STUFF*)
Your assignment is impossible to solve in C++. You either misunderstood something or there’s an error in the project specification. At any rate, we’ve got a problem here:
TEXT(a)+ is to be used to make the regular expression: std::regex("a+") without changing the fact that TEXT(a) expands to "a" [my emphasis]
TEXT(a) expands to "a" — meaning, we can just replace TEXT(a) everywhere in your example; after all, that’s exactly what the preprocessor does. In other words, you want the compiler to transform this C++ code
"a"+
into
std::regex("a+")
And that’s simply impossible, because the C++ preprocess does not allow expanding the + token.
The best we can do in C++ is use operator overloading to generate the desired code. However, there are two obstacles:
You can only overload operators on custom types, and "a" isn’t a custom type; its type is char const[2] (why 2? Null termination!).
Postfix-+ is not a valid C++ operator and cannot be overloaded.
If your assignment had just been a little different, it would work. In fact, if your assignment had said that TEXT(a)++ should produce the desired result, and that you are allowed to change the definition of TEXT to output something other than "a", then we’d be in business:
#include <string>
#include <regex>
#define TEXT(a) my_regex_token(#a)
struct my_regex_token {
std::string value;
my_regex_token(std::string value) : value{value} {}
// Implicit conversion to `std::regex` — to be handled with care.
operator std::regex() const {
return std::regex{value};
}
// Operators
my_regex_token operator ++(int) const {
return my_regex_token{value + "+"};
}
// more operators …
};
int main() {
std::regex x = TEXT(a)++;
}
You don't want to jab characters onto the end of macros.
Maybe you simply want something like this:
#define TEXT(a, b) #a #b
that way TEXT(a, +) gets expanded to "a" "+" and TEXT(a, *) to "a" "*"
If you need that exact syntax, then use a helper macro, like:
#define TEXT(a) #a
#define ADDTEXT(x, y) TEXT(x ## y)
that way, ADDTEXT(a, +) gets expanded to "a+" and ADDTEXT(a, *) gets expanded to "a*"
You can do it this way too:
#define TEXT(a) "+" // "a" "+" -> "a+"
#define TEXT(a) "*" // "a" "*" -> "a*"
Two string literals in C/C++ will be joined into single literal by specification.

How to remove the enclosing parentheses with macro?

No comma is allowed in a macro argument because it will be treated as more than one arguments and the preprocessing will be wrong. However, we can parenthesize the argument to let preprocessor treat it as one argument. Is there a macro or other techniques which can remove the enclosing parentheses?
For example, if I define a macro like
#define MY_MACRO(a, b) ...
and use it like
MY_MACRO( A<int, double>, text );
will be wrong. use it like
MY_MACRO( (A<int, double>), text)
with a macro or technique to remove the parentheses will be fine. Boost provides BOOST_IDENTITY_TYPE macro for only types but not general cases
#define ESC(...) __VA_ARGS__
then
MY_MACRO( ESC(A<int, double>), text );
might do what you want.
This macro trick is similar to Yakk's solution but removes the need to explicitly pass in another macro as a parameter.
#include <stdio.h>
#define _Args(...) __VA_ARGS__
#define STRIP_PARENS(X) X
#define PASS_PARAMETERS(X) STRIP_PARENS( _Args X )
int main()
{
printf("without macro %d %d %d %d %d %d\n", (5,6,7,8,9,10) ); // This actually compiles, but it's WRONG
printf("with macro %d %d %d %d %d %d\n", PASS_PARAMETERS((5,6,7,8,9,10)) ); //Parameter "pack" enclosed in parenthesis
return 0;
}
Of course you could get creative by making the PASS_PARAMETERS macro into a variadic macro and pass in multiple parameter packs.
Only maybe removing parentheses:
If you need to strip one layer of parenthesis, but only if there are parenthesis to strip, this longer set of macros does the trick:
#define DEPAREN(X) ESC(ISH X)
#define ISH(...) ISH __VA_ARGS__
#define ESC(...) ESC_(__VA_ARGS__)
#define ESC_(...) VAN ## __VA_ARGS__
#define VANISH
This may be needed if you want to use MY_MACRO for different sets of datatypes:
#define MY_MACRO(a, b) DEPAREN(a), b
MY_MACRO( ({x, y, z}), text )
//> {x,y,z}, text
MY_MACRO( singlearg, text )
//> singlearg, text
How it works:
We start with DEPAREN(X) ESC(ISH X). If X has parenthesis, we get ESC(ISH(X)). If X does not have parenthesis, we get ESC(ISH X).
We then expand ESC(...) into ESC_(__VA_ARGS__), which expands the interior.
ISH(...) turns into ISH __VA_ARGS__, which strips one layer of parentheses from X. Now, regardless of whether or not X originally had parenthesis, we have ESC_(ISH X).
We now need to get rid of ISH. However, because we already defined ISH(...), we can't also define it as #define ISH . That's why we concatenate it with another token (VAN) to get VANISH X.
VANISH is defined as , so we are finally left with X, sans parentheses.
A simple hack could be to use variadic macros:
#define MY_MACRO(a, b...) ...
Then you can use it like:
MY_MACRO(text, A<int, double>)
The comma in the second argument is still interpreted as the argument separator (meaning the macro is actually called with three arguments), but it's expanded inside the macro, making the behavior the same. The variadic argument has to be last in the macro, however.

c/c++ (VS2008) enclose macro param in quotes

For a lot of function calls in a C app that needs some degree of debugging I wanted to add a macro to ease the typing that I had to do.
right now I am calling a function like this:
aDebugFunction(&ptrToFunction, __LINE__, "ptrToFunction", param1, param2, etc)
So I thought lets write a macro that does the first 3 parameters for me, like this:
#define SOMEDEFINE(x) &x, __LINE__, "x"
However, as most of you will immediately know, this won't work it won't replace "x" with the name that x has been given but will just pass "x" as 3rd parameter.
My knowledge of this preprocessor macro happening stuff is quite limited and thus my googling-ability is also quite useless due to not knowing where to search for exactly.
I hope one of you guys/girls could give me either a solution or point me in the right direction.
You need to use the # convert token to string command of the preprocessor. You should define your second macro this way:
#define SOMEDEFINE(x) &x, __LINE__, # x
Or if x can also be a macro call, and you want the string to contains the expansion of the macro, you need to use an auxiliary macro:
#define TOKEN_TO_STRING(TOK) # TOK
#define STRINGIZE_TOKEN(TOK) TOKEN_TO_STRING(TOK)
#define SOMEDEFINE(x) &x, __LINE__, STRINGIZE_TOKEN(x)
For example, if you have the following code:
#define SHORT_NAME a_very_very_very_long_variable_name
SOMEDEFINE(SHORT_NAME)
Then, with the first macro, it will expand to
&a_very_very_very_long_variable_name, __LINE__, "SHORT_NAME"
While, with the second macro, it will expand to:
&a_very_very_very_long_variable_name, __LINE__, "a_very_very_very_long_variable_name"
You can actually do a lot better than that: #define SOMEDEFINE( X, ... ) aDebugFunction( &(X), __LINE__, #X, __VA_ARGS__ )
You could then simply call into this code like this: SOMEDEFINE( ptrToFunction, param1, param2, etc )
And that would effectively call: aDebugFunction( &( ptrToFunction ), __LINE__, "ptrToFunction", param1, param2, etc )

C++ Macros: manipulating a parameter (specific example)

I need to replace
GET("any_name")
with
String str_any_name = getFunction("any_name");
The hard part is how to trim off the quote marks. Possible? Any ideas?
How about:
#define UNSAFE_GET(X) String str_##X = getFunction(#X);
Or, to safe guard against nested macro issues:
#define STRINGIFY2(x) #x
#define STRINGIFY(x) STRINGIFY2(x)
#define PASTE2(a, b) a##b
#define PASTE(a, b) PASTE2(a, b)
#define SAFE_GET(X) String PASTE(str_, X) = getFunction(STRINGIFY(X));
Usage:
SAFE_GET(foo)
And this is what is compiled:
String str_foo = getFunction("foo");
Key points:
Use ## to combine macro parameters into a single token (token => variable name, etc)
And # to stringify a macro parameter (very useful when doing "reflection" in C/C++)
Use a prefix for your macros, since they are all in the same "namespace" and you don't want collisions with any other code. (I chose MLV based on your user name)
The wrapper macros help if you nest macros, i.e. call MLV_GET from another macro with other merged/stringized parameters (as per the comment below, thanks!).
One approach is not to quote the name when you call the macro:
#include <stdio.h>
#define GET( name ) \
int int##name = getFunction( #name ); \
int getFunction( char * name ) {
printf( "name is %s\n", name );
return 42;
}
int main() {
GET( foobar );
}
In answer to your question, no, you can't "strip off" the quotes in C++. But as other answers demonstrate, you can "add them on." Since you will always be working with a string literal anyway (right?), you should be able to switch to the new method.