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__); }
Related
I would like to define a macro to concat __func__ (or __FUNCTION__) with __LINE__:
The following works fine:
// macro_test.cc
#include <iostream>
#define STR2(X) #X
#define STR(X) STR2(X)
#define FILE_LOCATION __FILE__ ":" STR(__LINE__) " "
int main() {
std::cout << FILE_LOCATION << "is <file_name>:<line_number>" << std::endl;
return 0;
}
And here is the output
$ ./a.out
macro_test.cc:8 is <file_name>:<line_number>
However the following gives a compilation error (I just replaced __FILE__ with __func__):
// macro_test.cc
#include <iostream>
#define STR2(X) #X
#define STR(X) STR2(X)
#define FUNC_LOCATION __func__ ":" STR(__LINE__) " "
int main() {
std::cout << FUNC_LOCATION << "is <function_name>:<line_number>" << std::endl;
return 0;
}
~$ gcc macro_test.cc
macro_test.cc: In function ‘int main()’:
macro_test.cc:5:32: error: expected ‘;’ before string constant
#define FUNC_LOCATION __func__ ":" STR(__LINE__) " "
^
macro_test.cc:8:16: note: in expansion of macro ‘FUNC_LOCATION’
std::cout << FUNC_LOCATION << "is <function_name>:<line_number>" << std::endl;
Does anyone know the reason for this and how can I achieve this?
I am using gcc 5.4.0 on Linux (Ubuntu 18.04).
gives a compilation error [...] anyone know the reason for this
__func__ is a variable:
static const char __func__[] = "function-name";
It is not to a (string) literal (to which for example __FILE__ "expands".)
(docs are here: https://gcc.gnu.org/onlinedocs/gcc/Function-Names.html)
Instead of trying to stitch together incompatible types into a single string, you could have an immediately invoked function expression (borrowing from JavaScript terminology) as the macro implementation.
Since it is being immediately executed, I pass in the two preprocessor identifiers as parameters.
They shouldn't be baked into the body of the lambda because then the __func__ will reflect the lambda rather than the routine invoking the lambda.
#include <sstream>
#define FUNC_LOCATION \
[](auto fn, auto ln) { \
std::stringstream ss;
ss << fn << ":" << ln << " "; \
return ss.str(); \
}(__func__, __LINE__)
int main() {
std::cout << FILE_LOCATION << "is <file_name>:<line_number>" << std::endl;
return 0;
}
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;
}
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"
1.#define debug(...) printf( __VA_ARGS__)
2.#define debug(...) std::cout<< __VA_ARGS__
Apparently, 1 is ok, 2 will get error when compiles.
Is there any possibility to use "std::cout" with variable arguments?
What's the point of this macro?
'debug' macro use to print something to debug the code.
void test(const classtype1 &obj1,const classtype2 &obj2)
{
// rewrite operator<<
debug(obj1,obj2);
//if use printf, I must call tostring method(or something likes that) to
//series the object to string.
debug(obj1.tostring(),obj2.tostring());
...
}
You can do something like:
#define DEBUG(x) do { std::osacquire( std::cerr ) << __FILE__ << ":" << __LINE__ << " " << x << std::endl; } while (0);
And then wherever you want to use the macro:
DEBUG( obj1.tostring() + " some stuff " + obj2.tostring() )
I am wondering if how I can write a function to detect the parameter type, value and function name and return value of another function.
For example. I have a function:
double average(string datapath, double *data, int numofinput)
{
// some code here
}
I want to have another function, such as detector(), which can be inserted into the function to be detected, like
double average(string datapath, double *data, int numofinput)
{
// some code here
detector();
}
and the detector will return:
name: average
returned value: 2.43
pathname: string='C:/Users/Nick/Data/'
data: pointer=0x0065
numofinput: int=17
Somthing like that. Any suggestion is highly appreciated. Thanks.
Nick
In general this can't be done:
detector would need to show the return value before you actually return anything, which is same as mind reading
when a binary is built, the names of the functions are not available inside it (in general, except for exports)
your average function might not be a function at all, as compiler could inline it.
For specific cases, however, you could be able to get this information - under assumption that you have debug symbols available, which in general you don't.
Here's an (untested) idea:
#define DETECTOR(name, ...) detector_wrapper(name, #name, ##__VA_ARGS__)
template <typename R, typename ...Args, typename ...Brgs>
R detector_wrapper(R(&f)(Args...), char const * name, Brgs &&... brgs)
{
auto && result = f(std::forward<Brgs>(brgs)...);
std::cout << "Function name: " << name << std::endl
<< "Return type: " << demangle(R) << std::endl
<< "Return value: " << result << std::endl;
return result;
}
Usage:
double d = DETECTOR(average, path, data, n);
With a bit more work you can also print the types of the arguments and their values, though not their names (obviously, since the names are not part of the declaration, only of the definition).
Ok, here's another way to do it, including printing parameter names and types. It is not very elegant for two reasons:
It requires a new macro for every number of parameters you send, and ...
It's freaking macros! I've never seen them used elegantly (and this is no exception).
So here goes:
#include <iostream>
#define DETECTOR_0ARG_FUNC(RETTYPE, NAME) \
RETTYPE NAME() \
{ \
std::cout << "Function Name: " #NAME << std::endl; \
std::cout << "Returns: " #RETTYPE << std::endl; \
std::cout << "No Parameters" << std::endl;
#define DETECTOR_1ARG_FUNC(RETTYPE, NAME, PARAM1TYPE, PARAM1NAME) \
RETTYPE NAME(PARAM1TYPE PARAM1NAME) \
{ \
std::cout << "Function Name: " #NAME << std::endl; \
std::cout << "Returns: " #RETTYPE << std::endl; \
std::cout << "Pameter 1 (" #PARAM1TYPE " " #PARAM1NAME "): " << PARAM1NAME << std::endl;
#define DETECTOR_RETURN(RETTYPE, VALUE) \
RETTYPE __retval = (VALUE); \
std::cout << "Returning: " << __retval << std::endl << std::endl; \
return __retval;
#define DETECTOR_END_FUNC \
}
DETECTOR_0ARG_FUNC(int, GetFiveFactorial)
int result = 1;
for(int i=5; i>0; i--)
{
result = result * i;
}
DETECTOR_RETURN(int, result)
DETECTOR_END_FUNC
DETECTOR_1ARG_FUNC(int, GetFactorial, int, initVal)
int result = 1;
for(int i=initVal; i > 0; i--)
{
result = result * i;
}
DETECTOR_RETURN(int, result);
DETECTOR_END_FUNC
int main(int argc, char **argv)
{
GetFiveFactorial();
GetFactorial(7);
return 0;
}
The output:
Function Name: GetFiveFactorial
Returns: int
No Parameters
Returning: 120
Function Name: GetFactorial
Returns: int
Pameter 1 (int initVal): 7
Returning: 5040
I kindof don't recommend that you do this. But from a theoretical standpoint, it is possible this way.