Is there a way to make macro using #define, which will take two arguments and "return" string in specified format with values of given arguments?
Something like this:
#define MACRO( x, y ) ( "OK ", x, " ", y, " \a\b" ) // i know this doesn't work
int main ()
{
int a = 3,
b = -1;
std::cout << MACRO( a, b ) << std::endl; // this should print following string: "OK 3 -1 \a\b"
return 0;
}
Related
I want to write a macros to print pairs of {variable name, variable value}. The variables are supposed to be arguments of variadic macros.
I made a simple code, that produces compilation error: "expected expression" in cases when number of variables to print is less than maximum possible number.
#define IS_EMPTY(...) ( sizeof( (char[]){#__VA_ARGS__} ) == 1 )
#define PRINT_VAR(x) std::cout << "\"" << #x << "\": " << (x) << " ";
#define PRINT_VARS3(x, ...) {PRINT_VAR(x); }
#define PRINT_VARS2(x, ...) {PRINT_VAR(x); \
if constexpr (not IS_EMPTY(__VA_ARGS__)) PRINT_VARS3(__VA_ARGS__); }
#define PRINT_VARS1(x, ...) {PRINT_VAR(x); \
if constexpr (not IS_EMPTY(__VA_ARGS__)) PRINT_VARS2(__VA_ARGS__); }
#define PRINT_VARS(x, ...) {PRINT_VAR(x); \
if constexpr (not IS_EMPTY(__VA_ARGS__)) {\
PRINT_VARS1(__VA_ARGS__); \
} \
std::cout << "\n";}
int i = 100;
float j = 200.5;
int k = 300;
float l = -0.576f;
PRINT_VARS(i, j, k, l); // works fine
//PRINT_VARS(i, j); // compilation error
Thing that I cant understand, if I remove << (x) from second line, PRINT_VARS work with different number of arguments.
What is the reason and how to fix it?
Thank you!
Removing << (x) from the second line makes code compliable and working except it cant printout the variables values.
I expect the compiler not to check if constexpr branches at 0 condition. But it looks like empty
VA_ARGS passed to PRINT_VAR macros that leads to this error.
I have tried this code with gcc12 and clang14 compilers.
I have a 'system' to generate classes using macros (there is unfortunately no other way).
In some cases, for example for an initializer list, this leads to a trailing comma
that I'd like to get rid of:
#define REMOVE_TRAILING_COMMA(...) ?what to put here?
#define FOO a, b, c, d, e, f, g, h,
REMOVE_TRAILING_COMMA(FOO) --> expands to a, b, c, d, e, f, g, h
If it just removes the last argument that would be fine too, of course.
Aka if REMOVE_TRAILING_COMMA(a, b, c) expands to a, b.
The macro will always get at least two arguments, so the minimal case
would be: REMOVE_TRAILING_COMMA(a,) --> expands to a.
Is this even possible? I searched for a few hours with Google, but
nothing comes up.
I would be nice to use #define REMOVE_FIRST(a, ...) __VA_ARGS__, but that would require reversing macro arguments order. I do not see a way to do it (other then overloading it anyway). So overload the macro on count of arguments and enumerate each overload to remove trailing argument:
// example macro overoad for up to 9 args
// TODO: write REMOVE_TRAILING_COMMA_{1,2,3,4,5....} for each case
#define REMOVE_TRAILING_COMMA_8(_1,_2,_3,_4,_5,_6,_7,_8) \
_1,_2,_3,_4,_5,_6,_7
#define REMOVE_TRAILING_COMMA_9(_1,_2,_3,_4,_5,_6,_7,_8,_9) \
_1,_2,_3,_4,_5,_6,_7,_8
#define REMOVE_TRAILING_COMMA_N(_1,_2,_3,_4,_5,_6,_7,_8,_9,N,...) \
REMOVE_TRAILING_COMMA_##N
#define REMOVE_TRAILING_COMMA(...) \
REMOVE_TRAILING_COMMA_N(__VA_ARGS__,9,8,7,6,5,4,3,2,1)(__VA_ARGS__)
#define FOO a, b, c, d, e, f, g, h,
REMOVE_TRAILING_COMMA(FOO) --> expands to a, b, c, d, e, f, g, h
The following was added by Carlo Wood:
Thanks! I wrote a small program to generate the above, so it is
easy to increase the maximum number of arguments that this still works with:
#include <string>
#include <iostream>
#include <sstream>
std::string args1_N(int n)
{
std::ostringstream ss;
char const* prefix = "_";
for (int a = 1; a <= n; ++a)
{
ss << prefix << a;
prefix = ",_";
}
return ss.str();
}
int main()
{
int const max_args = 9;
for (int n = 1; n <= max_args + 1; ++n)
std::cout << "#define REMOVE_TRAILING_COMMA_" << n << "(" << args1_N(n) <<
") \\\n " << args1_N(n - 1) << std::endl;
std::cout << "#define REMOVE_TRAILING_COMMA_N(" << args1_N(max_args + 1) << ",N,...) \\\n" <<
" REMOVE_TRAILING_COMMA_##N\n";
std::cout << "#define REMOVE_TRAILING_COMMA(...) \\\n" <<
" REMOVE_TRAILING_COMMA_N(__VA_ARGS__";
for (int a = max_args + 1; a > 0; --a)
std::cout << "," << a;
std::cout << ")(__VA_ARGS__)" << std::endl;
}
I need to understand how this code works:
#define foo1( a ) (a * a) // How does this work?
inline int foo2( int a ) { return (a * a); }
int goo1( int x ) { return foo1(foo2(x)); }
int goo2( int& x ) { return x = foo2(foo1(x)); }
int goo3( int& x, int y ) { return foo2(foo1(y + 1)); }
void goo4( int& x, int y ) { x = foo1(foo2(y + 1)); }
int main(){
int i = 2, j = 1, a = 2+3;
cout << "foo1 = " << foo1( 1+2 ) << "\n"; // How does this work?
cout << "foo2 = " << foo2( 2 + 1 ) << "\n";
cout << "goo1 = " << goo1( i ) << "\n";
cout << "goo2 = " << goo2( j ) << "\n";
cout << "goo3 = " << goo3( i, j ) << "\n"; // How does this work?
goo4( i, j );
cout << " i = " << i << " j = " << j << "\n";
}
But I do not seem to be able understand the behaviour of this function:
#define foo1( a ) (a * a)
and hence I don't understand the output of these two function calls:
foo1( 1+2 )
goo3( i, j )
This is the output of the program:
foo1 = 5
foo2 = 9
goo1 = 16
goo2 = 1
goo3 = 9
i = 16 j = 1
I can't see why foo1 is not behaving like foo2. Would someone explain to me how this #define macro works?
NOTE: I must not change the code, I am only trying to understand the output.
Well, it's really simple.
foo1( 1 + 2 )
will turn into:
( 1 + 2 * 1 + 2 )
which is actually:
1 + 2 + 2 = 5
This is how macros work.
Macros are not functions.
Macros do TEXT replacement. So when you have
#define foo1( a ) (a * a)
any instance of foo1( ... ) with anything between then parenthesis will be expanded AS TEXT, not as an expression. So when you have foo1( 1 + 2 ) it turns into ( 1 + 2 * 1 + 2 )
Macro is not a function.
The compiler will expand all macros and then compile it. To see the expanded code, you can use the following command using -E option in gcc:
gcc -E <source code> -o <preprocessed file name>
Or in Visual C++, under Configuration Properties->C/C++->Preprocessor, set "Generate Preprocessed File".
BTW, your macro is problematic.
You should use
#define foo1( a ) ((a) * (a))
instead of
#define foo1( a ) (a * a)
The difference is, the foo1 defined by #define is NOT a function, while foo2 is.
In compilation process, the compiler will replace the foo1(parameter) keyword in your code with (parameter * parameter).
Meaning,
cout << "foo1 = " << foo1( 1+2 ) << "\n"; // How does this work?
will be replaced by the following code,
cout << "foo1 = " << ( 1+2 * 1+2 ) << "\n"; // How does this work?
(Because the parameter here is 1+2, instead of 3.)
The result is 1+2 * 1+2, which is 5.
Now let look at foo2, since it is an inline function, the compiler will not replace it. When your code is compiled into an executable file, and the executable file is executed, the 2 + 1 expression will be calculated first, and the result, 3, will then be passed to foo2().
In conclusion, the difference really lies in the compilation of your code. You may need more knowledge on what happens there.
I can define a macros which print only fixed variable count, for example:
#define PRINT_PARAMS(param) std::cout << "test: " << std::string( #param ) << " = " << param << "\n";
// using:
int varI = 5;
PRINT_PARAMS( varI );
// output:
test: varI = 5
How to define a macros which will do something like that:
PRINT_PARAMS( varI1, strValue2, floatValue3, doubleValue4 );
// output:
varI1 = 5, strValue2 = some string, floatValue3 = 3.403f, ....
I mean any number of input parameters.
#include <string>
#include <iostream>
//"for each" macro iterations
#define FE_1(Y, X) Y(X)
#define FE_2(Y, X, ...) Y(X)FE_1(Y, __VA_ARGS__)
#define FE_3(Y, X, ...) Y(X)FE_2(Y, __VA_ARGS__)
#define FE_4(Y, X, ...) Y(X)FE_3(Y, __VA_ARGS__)
#define FE_5(Y, X, ...) Y(X)FE_4(Y, __VA_ARGS__)
//... repeat as needed
//the "for each" call
#define GET_MACRO(_1,_2,_3,_4,_5,NAME,...) NAME
#define FOR_EACH(action,...) \
GET_MACRO(__VA_ARGS__,FE_5,FE_4,FE_3,FE_2,FE_1)(action,__VA_ARGS__)
//function to print a single
#define PRINT_SINGLE(param) std::cout << "test: " << std::string( #param ) << " = " << param << "\n";
//function to print n amount
#define PRINT_PARAMS(...) FOR_EACH(PRINT_SINGLE,__VA_ARGS__)
int main(){
std::string s1 = "hello";
float f = 3.14;
int i = 42;
PRINT_PARAMS(s1,f,i)
}
Don't have a compiler to hand but was wondering if the following variadic macro would work (or at least help give you an idea.)
#define PRINT_PARAMS(param) std::cout << "test: " << std::string( #param ) << " = " << param << "\n";
#define PRINT_PARAMS(a, ...) { PRINT_PARAMS((a)); PRINT_PARAMS(__VA_ARGS__); }
I have simple logging class as below.
#include <iostream>
#include <string>
using namespace std;
class log
{
public:
log(){};
~log(){};
log & operator << ( int x ){ cout << x; return * this;}
log & operator << ( string x ){ cout << x; return * this;}
log & operator << ( log & (log::*pf)() ){ (this->*pf)(); return * this;}
log & end( ) { cout << "\r\n"; return * this;}
};
log l;
#define end &log::end;
#define error( z ) l << "ERROR " z << end;
#define warn( z ) l << "WARN " z << end;
int main()
{
int y = 20;
error ( << y );
}
Is there any way that I can write my code in main like this?
error << y;
Basic idea here, is to avoid user to use macro end
i.e. I do not want user to code like below
error << y << end;
Look like you are reinventing the square wheel to me ! Indeed, there are a lot of logger library out there (boost.log is a good one). Another solution is to have the user write the standard syntax including the call to std::endl:
error << x << std::endl;
warn << y << std::endl;
You can do that by passing a string "warn" or "error" to the construtor of class log.
You have to intercept the std::endl parameter as described in Overload handling of std::endl?.
What about:
#define LOG(Msg) do { l << Msg << ::std::endl; } while(0)
Log("Hello" << "World");
Note: I use a macro like this in debug builds and make it ((void)0) in release builds.
For common logging you should not use a macro and may consider stream manipulators.
One option would be to remove your global variable and use your destructor to write the newline by having the macros create a scope so the object is destroyed:
#define error( z ) {log l; l << "ERROR " z; }
#define warn( z ) {log l; l << "WARN " z; }
That would yield code close to what it appears you want without your end macro:
int y = 20, z = 40;
error ( << y << " " << z);
If you like that approach you might want to look into improving the macro so log levels are enforced in the macro itself so objects are not created with every log message that have nothing to do, if performance at that level matters to you.
Don't see a plug for POCO logging anywhere in here, that's what I use. Not saying that would work for you, it's just what I like for my particular needs.
You may create class:
class PrefixLog
{
public:
explicit PrefixLog(const char* prefix) : prefix(prefix) {}
template <typename T>
log& operator << (const T& t) const { return l << prefix << t << &log::end; }
private:
const char* prefix;
};
PrefixLog error("ERROR ");
PrefixLog warning("WARN ");
And then
warning << y;
error << y;