Is there anyway to use for loop with string macro? - c++

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.

Related

How to join two table generating macros into a large one using the C++ preprocessor using a comma

I want to generate several pieces of code for several different values using the C++ preprocessor. I entered all of these values into a table generation macro. However, some parts of the code only have to be generated for certain (disjunct) subsets of the values. Hence, I would like to have small table generation macros and then merge them together into a large one (for the code that has to be generated for all of them). This part works flawlessly so far.
However, I require to use a comma as a seperator for some parts of the code (precisely to generate an enum). Unfortunately, this comma is replaced too early (i.e. before the function call of the macro is replaced). Here comes an example which should illustrate my problem:
#include <iostream>
#define A(F, SEP) F(one) SEP F(two)
#define B(F, SEP) F(three) SEP F(four)
#define C(F, SEP) A(F, SEP) SEP B(F, SEP)
#define SOME_F(x) x
#define SOME_SEP ,
enum {C(SOME_F, SOME_SEP)} ENUM;
int main()
{
#define ANOTHER_F(x) std::cout << #x << std::endl;
#define ANOTHER_SEP
A(ANOTHER_F, ANOTHER_SEP)
return 0;
}
Here I want to generate an enum containing all values (it's unused in the example but in my actual code I require it) and print all values of the subset A. If I try to compile this example, it fails with the error error: macro "A" passed 3 arguments, but takes just 2 (same message for B). The reason for this seems to be, that the SOME_SEP macro is replaced before A is substituted (and an attempt to use A(F, ,) is made).
A rather simple (but ugly) fix for this is to replace the SEP argument to be a function-like instead of an object-like macro (one has to add parentheses to each call though). However, I would like to solve this using an object-like macro. During my web search I discovered a lot of people with a similar problem, but they wanted to pass a template-type (and hence can resolve the issue by using braces (which doesn't work for the comma as a seperator)).
Just use brackets and then remove them.
#include <iostream>
#define EXP(...) __VA_ARGS__
#define A(F, SEP) F(one) EXP SEP F(two)
#define B(F, SEP) F(three) EXP SEP F(four)
#define C(F, SEP) A(F, SEP) EXP SEP B(F, SEP)
#define SOME_F(x) x
enum {C(SOME_F, (,))} ENUM;
int main() {
#define ANOTHER_F(x) std::cout << #x << std::endl;
A(ANOTHER_F, ())
}
Overall, this is odd usage and looks odd. Consider using BOOST_PP_SEQ_FOR_EACH and similar FOREACH_* macros. It's odd to define list of elements inside a macro to iterate over - I would expect it to be defined outside and passed as parameter. Like:
#define LIST1 (one)(two)
#define CALLBACK(x) x
SUPER_FOREACH(LIST1, CALLBACK, (,))
Also see How to convert an enum type variable to a string? if you want to stringify an enum.

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.

Stringification of int in C/C++

The below code should output 100 to my knowledge of stringification. vstr(s) should be expanded with value of 100 then str(s) gets 100 and it should return the string "100". But, it outputs "a" instead. What is the reason? But, if I call with macro defined constant foo then it output "100". Why?
#include<stdio.h>
#define vstr(s) str(s)
#define str(s) #s
#define foo 100
int main()
{
int a = 100;
puts(vstr(a));
puts(vstr(foo));
return 0;
}
The reason is that preprocessors operate on tokens passed into them, not on values associated with those tokens.
#include <stdio.h>
#define vstr(s) str(s)
#define str(s) #s
int main()
{
puts(vstr(10+10));
return 0;
}
Outputs:
10+10
The # stringizing operator is part of the preprocessor. It's evaluated at compile time. It can't get the value of a variable at execution time, then somehow magically convert that to something it could have known at compile time.
If you want to convert an execution-time variable into a string at execution time, you need to use a function like std::to_string.
Since vstr is preprocessed, the line
puts(vstr(a));
is translated as:
puts("a");
The value of the variable a plays no role in that line. You can remove the line
int a = 100;
and the program will behave identically.
Stringification is the process of transforming something into a string. What your macro stringifies ?
Actually the name of the variable itself, this is done at compilation-time.
If you want to stringify and then print the value of the variable at execution-time, then you must used something like printf("%\n",v); in C or cout << v << endl; in C++.
A preprocessor macro is not the same thing as a function, it does not expand the arguments at runtime and sees the value, but rather processes it at preprocessing stage (which is before compilation, so it doesn't even know the variables dependency).
In this case, you've passed the macro a to stringify, which it did. The preprocessor doesn't care a is also the name of a variable.

Macro metaprogramming horror

I am trying to do something like:
custommacro x;
which would expand into:
declareSomething; int x; declareOtherthing;
Is this even possible?
I already tricked it once with operator= to behave like that, but it can't be done with declarations.
You can elide the parentheses as long as you are willing to accept two additions:
the whole code needs to be wrapped in a block macro
there needs to be something following the echo directive
e.g. thusly:
#define LPAREN (
#define echo ECHO_MACRO LPAREN
#define done )
#define ECHO_MACRO(X) std::cout << (X) << "\n"
#define DSL(X) X
...
DSL(
echo "Look ma, no brains!" done;
)
...
Reasons for this:
There is no way to make a function-like macro expand without parentheses. This is just a basic requirement of the macro language; if you want something else investigate a different macro processor
Therefore, we need to insert the parentheses; in turn we need to have something after the directive, like a done macro, that will expand to a form containinf the necessary close paren
Unfortunately, because the echo ... done form didn't look like a macro invocation to the preprocessor, it wasn't marked for expansion when the preprocessor entered it, and whether we put parens in or not is irrelevant. Just using echo ... done will therefore dump an ECHO_MACRO call in the text
Text is re-scanned, marked for expansion, and expanded again when it is the argument to a function-like macro, so wrapping the entire block with a block macro (here it's DSL) will cause the call to ECHO_MACRO to be expanded on this rescan pass (DSL doesn't do anything with the result: it exists just to force the rescan)
We need to hide the ( in the expansion of echo behind the simple macro LPAREN, because otherwise the unmatched parenthesis in the macro body will confuse the preprocessor
If you wanted to create an entire domain-specific language for such commands, you could also reduce the number of done commands by making the core commands even more unwieldy:
#define LPAREN (
#define begin NO_OP LPAREN 0
#define done );
#define echo ); ECHO_MACRO LPAREN
#define write ); WRITE_MACRO LPAREN
#define add ); ADD_MACRO LPAREN
#define sub ); SUB_MACRO LPAREN
#define NO_OP(X)
#define ECHO_MACRO(X) std::cout << (X) << "\n"
#define WRITE_MACRO(X) std::cout << (X)
#define ADD_MACRO(D, L, R) (D) = (L) + (R)
#define SUB_MACRO(D, L, R) (D) = (L) - (R)
#define DSL(X) DSL_2 X
#define DSL_2(X) X
int main(void) {
int a, b;
DSL((
begin
add a, 42, 47
sub b, 64, 50
write "a is: "
echo a
write "b is: "
echo b
done
))
return 0;
}
In this form, each command is pre-designed to close the preceding command, so that only the last one needs a done; you need a begin line so that there's an open command for the first real operation to close, otherwise the parens will mismatch.
Messing about like this is much easier in C than in C++, as C's preprocessor is more powerful (it supports __VA_ARGS__ which are pretty much essential for complicated macro metaprogramming).
Oh yeah, and one other thing -
...please never do this in real code.
I understand what you're trying to do and it simply can't be done. A macro is only text replacement, it has no knowledge of what comes after it, so trying to do custommacro x will expand to whatever custommacro is, a space, and then x, which just won't work semantically.
Also, about your echo hack: this is actually very simple with the use of operators in C++:
#include <iostream>
#define echo std::cout <<
int main()
{
echo "Hello World!";
}
But you really shouldn't be writing code like this (that is, using macros and a psuedo-echo hack). You should write code that conforms to the syntax of the language and the semantics of what you're trying to do. If you want to write to standard output use std::cout. Moreover, if you want to use echo, make a function called echo that invokes std::cout internally, but don't hack the features of the language to create your own.
You could use for-loop and GnuC statement expression extension.
#define MY_MACRO\
FOR_MACRO(_uniq##__COUNTER__##name,{/*declareSomething*/ },{ /* declareOtherthing */ }) int
#define FOR_MACRO(NAME,FST_BLOCK,SND_BLOCK)\
for(int NAME = ({FST_BLOCK ;0;}); NAME<1 ; NAME++,(SND_BLOCK))
It's "practically hygienic", though this means that whatever you do inside those code blocks wont escape the for-loop scope.

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.