preventing unexpected macro re-expansion with boost? [duplicate] - c++

This question already has answers here:
How do I temporarily disable a macro expansion in C/C++?
(6 answers)
Closed 5 years ago.
The goal here is to simply get a, b, c out instead of their actual values. The setup is "simple enough":
#include <boost/preprocessor/seq/for_each_i.hpp>
#include <boost/preprocessor/seq/for_each.hpp>
#include <boost/preprocessor/stringize.hpp>
#include <iostream>
// Define "invalid" sequence first
#define SEQ (a)(b)(c)
// Try to create "final" value with `std::string("elem")`
// Brought in for explicit `std::string`, but no dice
#define MAKE_XSTRING(x) MAKE_STRING(x)
#define MAKE_STRING(x) std::string(#x)
// oh, the humanity! vvvvvvvvvvvv or BOOST_PP_STRINGIZE
#define HUMANIZE(r, data, elem) (MAKE_XSTRING(elem))
#define SEQ_HUMAN BOOST_PP_SEQ_FOR_EACH(HUMANIZE,,SEQ)
So what I'm expecting at this point is what I have: a new sequence with (std::string("a")) etc:
// confirmation: vvvvvvvvvvvvvvvv
// warning: Humans: (std::string("a")) (std::string("b")) (std::string("c"))
#pragma message "Humans: " BOOST_PP_STRINGIZE(SEQ_HUMAN)
Thinking I'm so very clever and have gotten my values sorted out in some explicit strings, now I define the actual values for what the "real" code needs.
// Now that we have the "final" values, actually define the real values
// in real code, it's some lengthy nested namespaces (inconvenient to type)
#define a 123
#define b 456
#define c 789
And at long last, lets print them to make sure they aren't expanded:
// Let there be printing!
#define GOTTA_PRINT_EM_ALL(r,data,i,elem) << ((i)+1) << ". " << elem << std::endl
int main(int argc, const char **argv) {
std::cout << "Humans: " << std::endl
BOOST_PP_SEQ_FOR_EACH_I(GOTTA_PRINT_EM_ALL,,SEQ_HUMAN);
}
But it seems the aliens did indeed take over:
Humans:
1. 123
2. 456
3. 789
Given that they're supposed to be std::string("a")...how the heck are the real values getting back in there?! I thought maybe the ("a") from the std::string constructor was creating issues, but it doesn't seem so (BOOST_PP_STRINGIZE results in same behavior). Any suggestions?

The macro indeed expands into code tokens:
test.cpp|24 col 1| note: #pragma message: Humans: (std::string("123")) (std::string("456")) (std::string("789"))
Now when you insert the code tokens into your GOTTA_PRINT_EM_ALL macro, you get
<< ((0)+1) << ". " << std::string(\"123\") << std::endl << ((1)+1) << ". " << std::string(\"456\") << std::endl << ((2)+1) << ". << std::string(\"789\")" << std::endl
Completely expectedly printing
Humans:
1. 123
2. 456
3. 789
To get the "code tokens" you need to stringize them as well:
// Let there be printing!
#define GOTTA_PRINT_EM_ALL(r,data,i,elem) << ((i)+1) << ". " << BOOST_PP_STRINGIZE(elem) << std::endl
Printing
Humans:
1. std::string("123")
2. std::string("456")
3. std::string("789")
See it Live On Coliru
#include <boost/preprocessor/seq/for_each_i.hpp>
#include <boost/preprocessor/seq/for_each.hpp>
#include <boost/preprocessor/stringize.hpp>
#include <iostream>
#include <string>
#define a 123
#define b 456
#define c 789
#define SEQ (a)(b)(c)
// Try to create "final" value with `std::string("elem")`
// Brought in for explicit `std::string`, but no dice
#define MAKE_STRING(x) std::string(#x)
#define MAKE_XSTRING(x) MAKE_STRING(x)
#define HUMANIZE(r, data, elem) (MAKE_XSTRING(elem))
#define SEQ_HUMAN BOOST_PP_SEQ_FOR_EACH(HUMANIZE,,SEQ)
// Let there be printing!
#define GOTTA_PRINT_EM_ALL(r,data,i,elem) << ((i)+1) << ". " << BOOST_PP_STRINGIZE(elem) << std::endl
int main() {
std::cout << "Humans: " << std::endl
BOOST_PP_SEQ_FOR_EACH_I(GOTTA_PRINT_EM_ALL,,SEQ_HUMAN);
}

Related

Recursively including a header file over a list of values

Suppose I have an header that is meant to be included several times generating code from a template parameterised over a macro DATA. I use it in this way:
#define DATA this
#include <header.hpp>
#undef DATA
#define DATA that
#include <header.hpp>
#undef DATA
#define DATA the_other
#include <header.hpp>
#undef DATA
Is there a way to automate this repeated inclusion given a list of the values of DATA? Something like:
#define DATAS (this, that, the_other)
#include <header.hpp>
#undef DATAS
I tried with some __VA_OPT__ magic, and inside of header.hpp I can isolate the first element of the list and the tail of the list, but the problem is that I cannot redefine DATAS in terms of itself for the next inclusion.
Is this possible at all?
Yes, it is possible.
You can use Boost Preprocessor (which is independent of all other Boost Packages and only has to be downloaded, no library needs to be built or installed) to get the needed ready-to-use macros. You can also try to understand Boost Preprocessor and recreate the needed features.
The example is taken from Ari's answer. It could be expanded to provide several data elements to each iteration, e.g. for initializing the ints and floats with specific values.
// header.hpp - sample header, which uses DATA to create variables
// uses Boost preprocessor only for simple concatenation
// you can use your custom header here
#include <boost/preprocessor/cat.hpp>
int BOOST_PP_CAT(int_, DATA) = 1;
float BOOST_PP_CAT(float_, DATA) = 2.2f;
// main.cpp - wants to define lots of variables
// provides header name, list of symbol suffixes
// repeated.hpp will include header.hpp 3 times with DATA set to this, that and the_other
// (Space after REP_PARAMS is important)
#define REP_PARAMS ("header.hpp")(this, that, the_other)
#include "repeated.hpp"
#undef REP_PARAMS
#include <iostream>
using namespace std;
int main()
{
cout << "int_this: " << int_this << endl;
cout << "int_that: " << int_that << endl;
cout << "int_the_other: " << int_the_other << endl;
cout << "----------------------------------------------------------"
<< endl;
cout << "float_this: " << float_this << endl;
cout << "float_that: " << float_that << endl;
cout << "float_the_other: " << float_the_other << endl;
return 0;
}
// repeated.hpp - helper header
// all the magic
// it mostly extracts the REP_PARAMS sequence
// TODO error-checking, e.g. that REP_PARAMS exists and is a sequence of length two, that second element of REP_PARAMS is a tuple
#if !BOOST_PP_IS_ITERATING
// iteration has not started yet, include used boost headers
// initialize iteration with 3 parameters from 0 to < size of tuple,
// include itself (repeated.hpp)
#include <boost/preprocessor/iteration/iterate.hpp>
#include <boost/preprocessor/tuple/elem.hpp>
#include <boost/preprocessor/tuple/size.hpp>
#include <boost/preprocessor/seq/seq.hpp>
#define BOOST_PP_ITERATION_PARAMS_1 (3, (0, BOOST_PP_TUPLE_SIZE(BOOST_PP_SEQ_TAIL(REP_PARAMS)), "repeated.hpp"))
#include BOOST_PP_ITERATE()
#else
// set DATA to i-th element in tuple, include specified header (header.hpp)
#define DATA BOOST_PP_TUPLE_ELEM(BOOST_PP_ITERATION(), BOOST_PP_SEQ_TAIL(REP_PARAMS))
#include BOOST_PP_SEQ_HEAD(REP_PARAMS)
#undef DATA
#endif
The maximum list size is 256. By default it is limited to 64, but can be increased with the BOOST_PP_LIMIT_TUPLE macro.
I have to admit I wouldn't even consider using any preprocessing tricks for that. This is a classical scripting problem.
Instead you could write a small script that creates that header for you and inserts that at the beginning of the file. You could then add that as a step in your build system to run it. This technique gives you a LOT of power going forward:
You can add the same header to many scripts rather easily
You can see all the custom headers in a clean json format
You could easily get the script to add multiple #define <key> <value>-s before the include
You could change formatting easily and quickly
Here is an example script that does that:
import json
def prepend_headers(fout, headers):
for header in headers:
include = header['include']
define = header['define']
for k, v in define.items():
fout.write(f'#define {k} {v}\n')
fout.write(f'#include {include}\n')
for k, _ in define.items():
fout.write(f'#undef {k}\n')
fout.write('\n')
def main(configfile):
with open(configfile) as fin:
config = json.load(fin)
input_file = config['input']
with open(input_file) as fin:
input_content = fin.read()
output_file = config['output']
with open(output_file, 'w') as fout:
headers = config['headers']
prepend_headers(fout, headers)
fout.write(input_content)
if __name__ == '__main__':
import sys
configfile = sys.argv[1]
sys.exit(main(configfile))
If you use the following configuration:
{
"input": "class.cpp.template",
"output": "class.cpp",
"headers": [
{
"include": "<header.hpp>",
"define": {
"DATA": "this",
"OBJ": "him"
}
},
{
"include": "<header.hpp>",
"define": {
"DATA": "that"
}
},
{
"include": "<header.hpp>",
"define": {
"DATA": "the_other"
}
}
]
}
And the following template file:
#include <iostream>
class Obj {
};
int main() {
Obj o;
std::cout << "Hi!" << std::endl;
return 0;
}
The result you get is this:
#define DATA this
#define OBJ him
#include <header.hpp>
#undef DATA
#undef OBJ
#define DATA that
#include <header.hpp>
#undef DATA
#define DATA the_other
#include <header.hpp>
#undef DATA
#include <iostream>
class Obj {
};
int main() {
Obj o;
std::cout << "Hi!" << std::endl;
return 0;
}
Using a template class might be annoying, so you might decide to add some hints in the output file so you could "replace" them with every build you run.
This is not doable using preprocessor only. However, it is probably worth mentioning that there is something called X-Macro that could have been used for something close to what you are asking if you weren't using preprocessor macros for each case.
The reason is that it cannot be used here is that you cannot use #define or #include in the definition of a macro.
For example, this is doable for defining this, that and the_other as variables from a file called data.def that has them as a list:
// data.def
ELEMENT(this)
ELEMENT(that)
ELEMENT(the_other)
Then in main.cc:
//main.cc
#define ELEMENT(d) int int_##d = 1;
#include "data.def"
#undef ELEMENT
#define ELEMENT(d) int float_##d = 2.2;
#include "data.def"
#undef ELEMENT
int main() {
std::cout << "int_this: " << int_this << std::endl;
std::cout << "int_that: " << int_that << std::endl;
std::cout << "int_the_other: " << int_the_other << std::endl;
std::cout << "----------------------------------------------------------"
<< std::endl;
std::cout << "float_this: " << float_this << std::endl;
std::cout << "float_that: " << float_that << std::endl;
std::cout << "float_the_other: " << float_the_other << std::endl;
}
Output:
int_this: 1
int_that: 1
int_the_other: 1
---------------------------------------------------------------
float_this: 2
float_that: 2
float_the_other: 2
But something like this is not going to work because you would be defining a macro in another macro:
#define ELEMENT(d) #define DATA d; \
#include "data.def" \
#undef DATA
#undef ELEMENT

Evaluate macro depending if another macro is defined

The following preprocessor-based identifier-to-string lookup table:
#include <iostream>
// included generated file
#define KEY_a valueA
#define KEY_b valueB
///////
#define LOOKUP_(_key_) KEY_ ## _key_
#define QUOTE_(_str_) #_str_
#define EXPAND_AND_QUOTE_(_str_) QUOTE_(_str_)
#define LOOKUP(_key_) EXPAND_AND_QUOTE_(LOOKUP_(_key_))
int main() {
std::cout << LOOKUP(a) << std::endl;
std::cout << LOOKUP(b) << std::endl;
std::cout << LOOKUP(c) << std::endl;
}
Output:
valueA
valueB
KEY_c
The first #defines come from an #included header generated by an external script before the compilation.
The LOOKUP macro correctly handles existing key in the table, and substitutes the given value as string literal.
But for non-existing keys, it substitutes the key as string literal.
Is there a way to instead make it substitute a given constant for non-existing keys, without causing a compile-time error, and all within the preprocessing stage?
So for example, the LOOKUP(c) and LOOKUP(whatever) should all be substituted to "undefined", without c or whatever occuring in the included generated file.
The names of the keys should not be outputted to the compiled binary, so ideally they should never be seen by the compiler.
Here's a simple, if hacky, solution. By making the definition of KEY_x a list of two elements (the first of which will be ignored), it permits adding a default value:
#include <iostream>
// included generated file
#define KEY_a _,valueA
#define KEY_b _,valueB
///////
#define LOOKUP_(key) KEY_ ## key
#define QUOTE_(_,str,...) #str
#define EXPAND_AND_QUOTE_(...) QUOTE_(__VA_ARGS__)
#define LOOKUP(key) EXPAND_AND_QUOTE_(LOOKUP_(key),undefined)
int main() {
std::cout << LOOKUP(a) << std::endl;
std::cout << LOOKUP(b) << std::endl;
std::cout << LOOKUP(c) << std::endl;
}
Test on coliru

#defined functions can only accept raw input not variables?

I was working on a small application that I'm building a simple CLI for. I wanted my CLI to have some colors because who likes boring old white and black consoles?? (jk no offense if you do:))
Then as I was building onto it I seem to have run into a problem that I, unfortunately, don't understand :(. The problem lies in some borrowed code that is supposed to help me clean the code by wrapping all the necessary code into neat little functions or definitions (you'll see what I'm talking about soon). I don't really know how definitions work in C++ or at least the more advanced ones but here is the code I currently have for wrapping the CLI color code functions into:
Colors.h
#ifndef _COLORS_
#define _COLORS_
/* FOREGROUND */
#define RST "\x1B[0m" // RESET
#define KRED "\x1B[31m" // RED
#define KGRN "\x1B[32m" // GREEN
#define KYEL "\x1B[33m" // YELLOW
#define KBLU "\x1B[34m" // BLUE
#define KMAG "\x1B[35m" // MAGENTA
#define KCYN "\x1B[36m" // CYAN
#define KWHT "\x1B[37m" // WHITE
#define FRED(x) KRED x RST
#define FGRN(x) KGRN x RST
#define FYEL(x) KYEL x RST
#define FBLU(x) KBLU x RST
#define FMAG(x) KMAG x RST
#define FCYN(x) KCYN x RST
#define FWHT(x) KWHT x RST
#define BOLD(x) "\x1B[1m" x RST // BOLD
#define UNDL(x) "\x1B[4m" x RST // UNDERLINE
#endif /* _COLORS_ */
So the problem is that this below works:
std::cout << FBLU("Hello, World. I'm blue!") << std::endl;
and this doesn't...
std::string randomString = "Hello, World. I'm blue!";
std::cout << FBLU(randomString) << std::endl;
Again, I'm not too familiar with how "defined functions" work but I was just wondering if anybody could possibly show me a new method that accepts both the raw text input and a variable input to the defined functions. Also if you could help me understand how definitions work more in C++ that would be awesome as well.
Macros work the same way as if you copy-pasted the macro definition to the place where it's used.
So this works:
std::cout << FBLU("Hello, World. I'm blue!") << std::endl;
// same as
std::cout << "\x1B[34m" "Hello, World. I'm blue!" "\x1B[0m" << std::endl;
// same as
std::cout << "\x1B[34mHello, World. I'm blue!\x1B[0m" << std::endl;
(C++ has a rule whereby adjacent string literals get joined together. I imagine this rule was added so that you can do exactly what you're doing here)
And this doesn't work:
std::string randomString = "Hello, World. I'm blue!";
std::cout << FBLU(randomString) << std::endl;
// same as
std::cout << "\x1B[34m" randomString "\x1B[0m" << std::endl;
// oops, syntax error
The difference is because FBLU is a preprocessor macro (and NOT a function) that works as you expect ONLY if its parameter is a string literal. The preprocessor does TEXT substitution to produce source code - which is passed to a later phase of compilation.
The preprocessor will turn
FBLU("Hello, World. I'm blue!")
into
KBLU "Hello, World. I'm blue!" RST
which (by substituting the macros KBLU and RST) becomes
"\x1B[34m" "Hello, World. I'm blue!" "\x1B[0m"
which is a set of string literals, which get appended (again by the preprocessor) to become a single string literal
"\x1B[34mHello, World. I'm blue!\x1B[0m"
The net effect is that
std::cout << FBLU("Hello, World. I'm blue!") << std::endl;
is seen by the compiler as
std::cout << "\x1B[34mHello, World. I'm blue!\x1B[0m" << std::endl;
which is a perfectly valid code statement.
This doesn't work for
std::string randomString = "Hello, World. I'm blue!";
std::cout << FBLU(randomString) << std::endl;
since
FBLU(randomString)
is preprocessed to become
KBLU randomString RST
which (by substituting the macros KBLU and RST) becomes
"\x1B[34m" randomString "\x1B[0m"
Now, since randomString is an identifier (name of a variable, in this case), the preprocessor does no further macro substitution, and
std::cout << FBLU(randomString) << std::endl;
is seen by the compiler as
std::cout << "\x1B[34m" randomString "\x1B[0m" << std::endl;
which is not a valid statement.
The difference (depending on whether the argument to FBLU() is a string literal or a variable) is one of many reasons that usage of macros is actively discouraged in C++.
There are various alternatives that can be used instead, but the essential guideline is "Don't use macros".
For example, change the header files to convert the macros with no arguments into variable declarations, such as
#include <string> // needed in the header since we're using std::string
/* FOREGROUND */
const std::string RST = "\x1B[0m"; // RESET
const std::string KRED = "\x1B[31m"; // RED
// etc
and the macros with arguments into inline functions
inline std::string FRED(const std::string &x)
{
return KRED + x + RST;
}
After doing this, both of your examples will work as expected.
You are concatenating strings with macros, macros are not functions. You can't invoke macros with variables. For example the following program will print "hello world"
#include <iostream>
using std::cout;
using std::endl;
int main() {
cout << "hello " "world" << endl;
}
See https://wandbox.org/permlink/EbG5ZUgVfKLo9lEq
So when you "invoke" the macro, after preprocessing your code looks like this
std::cout << FBLU("Hello, World. I'm blue!") << std::endl;
std::cout << "\x1B[34m" "Hello, World. I'm blue!" "\x1B[0m" << std::endl;
You are essentially combining the arguments to the macro together before compilation at preprocessing time. So with variables in your example you get the following
std::cout << FBLU(randomString) << std::endl;
std::cout << "\x1B[34m" randomString "\x1B[0m" << std::endl;
Which is ill formed C++, since you can't concatenate non string literals with string literals like that.
Remember that macros do nothing but plain text replacement.
The compilation of a C++ program involves three steps: preprocessing, compilation, linking.
So, you see, preprocessing goes first. At that time content of variable is not known to preprocessor, so your second code snippet unrolls to the following:
std::string randomString = "Hello, World. I'm blue!";
std::cout << "\x1B[34m" randomString "\x1B[0m" << std::endl;
which produces syntax error.

VC++ marco, getting raw text of parameter

How do I get the text of the data given to value, not the value of the executed expression?
#define PRINT_VALUE(value) std::cout << "Value " << __RAWTEXT(value) << " is " << value << "\n";
__RAWTEXT is something I made up. Is there really something out there that does this though?
int testVariable = 5;
PRINT_VALUE(testVariable);
The output of this should be
Value testVariable is 5
Use the "stringize" operator # for this:
#define PRINT_VALUE(value) std::cout << "Value " << #value << " is " << value << "\n";
It's pretty straightforward, #TTT in a macro converts TTT to "TTT", a string literal.
It's worth mentioning that when the parameter is itself a macro, you'll get the name of the macro. However, if the parameter is passed to a subsequent macro, it's "unpacked". So you see these sometimes:
#define STRINGIZE2(X) #X
#define STRINGIZE(X) STRINGIZE2(X)
Here they are in action:
#define TEST Bob
std::cout << #TEST; //results in "TEST"
std::cout << STRINGIZE2(TEST); //results in "TEST"
std::cout << STRINGIZE(TEST); //results in "Bob"
Not relevent to your question but also notable is the "concat" macro operator ## which "glues" two bits of text togeather. std::st ## ing results in std::string. Useful in macros:
#define make_thing(X) \
structX##_class {
static const char* const name=#X;
};
make_thing(Foo);
std::cout << Foo_class::name;
And again, if a parameter is a macro, you get the macro name. So here's the de-macro macros:
#define GLUE2(X,Y) (X##Y)
#define GLUE(X,Y) GLUE2(X,Y)
#define HEY "HELLO"
#define THERE "WORLD"
std::cout << GLUE(HEY,THERE); //"HELLOWORLD"

variable + value macro expansion

I tried without any result.
My code looks like this:
#include "stdafx.h"
#include <iostream>
#define R() ( rand() )
#define H(a,b) ( a ## b )
#define S(a) ( # a )
#define CAT() H(S(distinct_name_), R())
int main(int argc, _TCHAR* argv[])
{
std::cout << CAT() << std::endl;
std::cout << CAT() << std::endl;
std::cout << CAT() << std::endl;
return 0;
}
I would like to get a result like this:
distinct_name_12233
distinct_name_147
distinct_name_435
as a result of concatenating
distinct_name_ (##) rand()
Right now I am getting an error:
term does not evaluate to a function taking 1 arguments.
Is this achievable ??
EDIT:
I finally succeeded after couple of hours. The preprocessor still does strange things I cannot understand completely. Here it goes:
#include "stdafx.h"
#include <iostream>
class profiler
{
public:
void show()
{
std::cout << "distinct_instance" << std::endl;
}
};
#define XX __LINE__
#define H(a,b) ( a ## b )
#define CAT(r) H(distinct_name_, r)
#define GET_DISTINCT() CAT(XX)
#define PROFILE() \
profiler GET_DISTINCT() ;\
GET_DISTINCT().show() ; \
int main(int argc, _TCHAR* argv[])
{
PROFILE()
PROFILE()
return 0;
}
And the output is:
distinct_instance
distinct_instance
Thanks #Kinopiko for __LINE__ hint. :)
No, you can't do that. Macros are a compile-time thing and functions are called only at run time, so there's no way you could get a random number from rand() into your macro expansion.
I see that a lot of people have already correctly answered this question, but as an alternative suggestion, if your preprocessor implements __TIME__ or __LINE__ you could get a result quite like what you want, with a line number or time concatenated, rather than a random number.
What you are actually getting is...
std::cout << distinct_name_rand() << std::endl;
distinct_name_rand() isn't a function, so it fails with a compile error.
Macros don't execute functions during compile time.
You must pass run-time computed value to the macro since macro are evaluated at compile-time.
Try:
#define H(a,b) ( a ## b )
#define S(a) ( # a )
#define CAT(r) H(S(distinct_name_), r)
std::cout << CAT(rand()) << std::endl;