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;
}
Related to my question Alternative to expanding templates in a switch statement trying to get Boost.Preprocessor to do a nested interation over a sequence.
#include <boost/preprocessor.hpp>
#include <iostream>
#define LASERTYPE_VALUES (EXCIMER)(GAS)(METALVAPOR)(SOLIDSTATE)(DYE)(SEMICONDUCTOR)(FREEELECTRON)(OTHER)
enum LaserType
{
BOOST_PP_SEQ_ENUM(LASERTYPE_VALUES)
};
#define LT_NESTED(maR, maToplevelType, maNestedType) \
std::cout << "Test nested: first=" << LaserType(maToplevelType) << " second=" << LaserType(maNestedType) << " \n";
#define LT_TOPLEVEL(maR, maUnused, maType) \
std::cout << "Test toplevel: " << LaserType(maType) << " \n"; \
BOOST_PP_SEQ_FOR_EACH_R(maR, LT_NESTED, maType, LASERTYPE_VALUES);
int main() {
BOOST_PP_SEQ_FOR_EACH(LT_TOPLEVEL, %%, LASERTYPE_VALUES);
}
This leads to this error:
test-pp.cpp: In function ‘int main()’:
test-pp.cpp:15:32: error: ‘LT_NESTED’ was not declared in this scope
BOOST_PP_SEQ_FOR_EACH_R(maR, LT_NESTED, maType, LASERTYPE_VALUES);
^
/usr/include/boost/preprocessor/seq/for_each.hpp:49:57: note: in expansion of macro ‘LT_TOPLEVEL’
# define BOOST_PP_SEQ_FOR_EACH_M_I(r, macro, data, seq) macro(r, data, BOOST_PP_SEQ_HEAD(seq))
^
test-pp.cpp:4:39: error: ‘EXCIMER’ cannot be used as a function
#define LASERTYPE_VALUES (EXCIMER)(GAS)(METALVAPOR)(SOLIDSTATE)(DYE)(SEMICONDUCTOR)(FREEELECTRON)(OTHER)
^
test-pp.cpp:15:51: note: in expansion of macro ‘LASERTYPE_VALUES’
BOOST_PP_SEQ_FOR_EACH_R(maR, LT_NESTED, maType, LASERTYPE_VALUES);
Reordering the macros doesn't help. There's something fundamentally wrong here, and it's likely trivial, but I haven't yet figured out how to do this and haven't seen any decent examples. If anyone had any suggestions, I'd be very interested to know what I'm doing wrong here.
https://groups.google.com/forum/#!topic/boost-list/jhN4NE9VAtg indicates that I might be running into reentrancy problems. It looks like I might be able to use BOOST_PP_FOR directly for the top level macro perhaps. If anyone had an example of that, it would be really useful.
I found a workaround in https://groups.google.com/forum/#!topic/boost-devel-archive/Tbcs4nn4sPE which gives this solution:
#include <boost/preprocessor.hpp>
#include <iostream>
#define LASERTYPE_VALUES (EXCIMER)(GAS)(METALVAPOR)(SOLIDSTATE)(DYE)(SEMICONDUCTOR)(FREEELECTRON)(OTHER)
enum LaserType
{
BOOST_PP_SEQ_ENUM(LASERTYPE_VALUES)
};
#define PP_SEQ_FOR_EACH_R_ID() BOOST_PP_SEQ_FOR_EACH_R
#define PP_DEFER(x) x BOOST_PP_EMPTY()
#define LT_NESTED(maR, maToplevelType, maNestedType) \
std::cout << "Test nested: first=" << LaserType(maToplevelType) << " second=" << LaserType(maNestedType) << " \n";
#define LT_TOPLEVEL(maR, maUnused, maType) \
std::cout << "Test toplevel: " << LaserType(maType) << " \n"; \
PP_DEFER(PP_SEQ_FOR_EACH_R_ID)()(maR, LT_NESTED, maType, LASERTYPE_VALUES);
int main() {
BOOST_PP_EXPAND(BOOST_PP_SEQ_FOR_EACH(LT_TOPLEVEL, %%, LASERTYPE_VALUES));
}
It's a bit esoteric but it compiles and functions as required.
Some time ago, I made this beautiful assert macro for c and c++ programs
#define ASSERT(truthy, message) \
if (!(truthy)) \
{\
cout << message << " on line " << __LINE__ << " in file " << __FILE__ << ". Check was " << #truthy << endl;\
}
Scatter ASSERT calls throughout your code, and it will warn you whenever the truthy value is not truthy! Very handy during development to remind you of potential mistakes.
ex
ASSERT(filesFound > 0, "Couldn't find any files, check your path!");
When filesFound is 0, the macro will print out
Couldn't find any files, check your path! on line 27 in file
openFiles.c. Check was filesFound > 0
Now what I want it to print, to give me even more relevant information, is the value of any variables passed into the truthy parameter. Like this
Couldn't find any files, check your path! on line 27 in file
openFiles.c. Check was filesFound > 0, filesFound is 0
This seems lisp-like territory, I wonder, is there any black magic c preprocessing that I can use to evaluate variables and functions to their values, without evaluating the truthy statement?
I assume to be disappointed.
An alternative solution which I've always used is to support varargs in the macro and then force the assert user to specify the relevant message / variables - it's a little bit of extra work each time, but on the plus side you can get exactly the formatting that you want and include information not available in the "truthy" bit, e.g:
#define ASSERT(truthy, message, ...) \
if (!(truthy)) \
{\
MyAssertHandler(__LINE__, __FILE__, #truthy, message, ##__VA_ARGS__);
}
Then you're handler is just a fairly standard var-arg function that can use e.g. vsnprintf to generate the message and output it, e.g. off the top of my head:
void MyAssertHandler(int line, const char* file, const char* expressionStr, const char* format, ...)
{
// Note: You probably want to use vsnprintf instead to first generate
// the message and then add extra info (line, filename, etc.) to
// the actual output
va_list args;
va_start(args, format);
vprintf(format, args);
va_end(args);
// Log to bug database, DebugBreak() if a debugger is attached, etc.
}
usage:
ASSERT(IsBlah(), "BlahBlah: x = %.2f, name = %s", GetX(), GetName());
I cannot imagine a way to do it... except by passing another parameter
#define ASSERT_PARAM(truthy, message, param) \
if (!(truthy)) \
{\
cout << message << " on line " << __LINE__ << " in file " << __FILE__ << ". Check was " << #truthy << ", value was " << param << endl;\
}
You would use it that way:
ASSERT_PARAM(filesFound > 0, "Couldn't find any files, check your path!", filesFound);
getting:
Couldn't find any files, check your path! on line 27 in file openFiles.c. Check was filesFound > 0, value was 0
What you are trying to do sounds very complicated. I'm afraid in C++ it's not possible.
Technically what you are evaluating is a bool expression so you can pass it to a parser whenever the assertion fails. The parser then will build the expression tree, get the leaves (elements of the expression) and return them. The returned values then should be printed out. To do that you will need support for reflection which is actually not supported in C++ AFAIK.
Maybe not the dream solution, but you can pass whole statements to a macro.
#define ASSERT(trusty, action) if (!trusty) { action }
ASSERT(trusty, cout << a << b;)
ASSERT(trusty, printf("%d, %f\n", a, b);)
I think you can split up the truthy Expression like they do it in the first answer here and then you can probably print the individual values. But I'm not sure if it actually works.
The printing could then be resulved using a variadic template function
Perhaps you could compromise and only allow 2 variables and 1 operator in the assertion expression? If so, you could make an ad hoc solution like this:
#include <iostream>
#include <string>
#define STRINGIFY(x) #x
#define BIN_ASSERT(obj1, op, obj2, msg) \
if(!(obj1 op obj2)) \
{ \
std::cout << msg << " on line " << __LINE__ \
<< " in file " << __FILE__ \
<< "." << std::endl \
<< "Check was " \
<< STRINGIFY(obj1) STRINGIFY(op) STRINGIFY(obj2) \
<< "." << std::endl \
<< "Operator " << #obj1 << ": " << obj1 \
<< "." << std::endl \
<< "Operator " << #obj2 << ": " << obj2 \
<< "." << std::endl; \
}
int main (void)
{
int x = 2;
int y = 3;
std::string s1 = "hello";
std::string s2 = "world";
BIN_ASSERT(1, +, -1, "Value zero"); std::cout << std::endl;
BIN_ASSERT(x, ==, y, "Numbers not equal"); std::cout << std::endl;
BIN_ASSERT(s1, ==, s2, "Strings not equal"); std::cout << std::endl;
}
Output:
Value zero on line 30 in file test.c.
Check was 1+-1.
Operator 1: 1.
Operator -1: -1.
Numbers not equal on line 31 in file test.c.
Check was x==y.
Operator x: 2.
Operator y: 3.
Strings not equal on line 32 in file test.c.
Check was s1==s2.
Operator s1: hello.
Operator s2: world.
I wonder if having the macro take a message is really that useful. A failed assertion is a message to the developer that there is a bug in the code that caused an exceptional behaviour or put the program in an unacceptable state. The user has less to do with it (if they even have access to the source code).
The code below defines an ASSERT macro that takes a boolean expression, evaluates it and prints an informational message. The message contains a value that you've asked to inspect upon failing the assertion.
The macro, just like the standard assert() macro (in <cassert>) goes on to call abort() (from <cstdlib>) to cause an abnormal program termination. This is what you want, because the program entered a state in which it didn't know what more to do.
I'm using std::printf() here for brevity. You do whatever you want.
#include <cstdlib>
#include <cstdio>
#define ASSERT(value, inspect) \
if (!(value)) { \
std::printf("ASSERTION FAILED: '%s', %s is %d: %s#%s:%d\n", #value, \
#inspect, inspect, __func__, __FILE__, __LINE__); \
abort(); \
}
int foo() { return 42; }
int main()
{
// ...
ASSERT(foo() - 40 == 1, foo());
//...
}
Program run:
$ ./a.out
ASSERTION FAILED: 'foo() - 40 == 1', foo() is 42: main#prog.cc:16
Abort
It's not possible to do exactly what you ask for without adding more parameters to the macro. At some point you'll have to stop and realize that you're spending time on creating a text string that you do not want to see.
You need to build an expression 'grabber' / builder.
The macro would become something like:
#define ASSERT_PARAM(truthy, message, param) \
if (!(truthy)) \
{\
Grabber g;
g << #truthy; // grab expression as string
g % truthy; // grab expression and values
cout << message << " on line " << __LINE__ << " in file " << __FILE__ << ". Check was " << #truthy << ", value was " << param << endl;\
cout << g; \
}
What does Grabber do?
It is a bunch of crazy C++ that builds up an expression. It would overload every operator to 'grab' the params of the operator. Every operator returns a reference to the grabber, so it can grab the next operator. ie
Grabber g;
g % filesFound > 0;
Since % (and * and /) have high precedence, the above parses like:
((g % filesFound) > 0)
If template<typename T> Grabber::operator%(T const & val) just records (or prints) the value passed in (ie filesFound), and - importantly - returns itself (g) so that it becomes part of the next expression: ie it becomes g > 0. Causing template<typename T> Grabber::operator>(T const & val) to be called, and > 0 to be recorded.
Then cout << g can spew out everything grabbed.
As mentioned above "It is possible — the Catch library does it. But it’s hellishly difficult".
P.S. you should wrap your macro in a do ... while 0 like this:
#define ASSERT_PARAM(truthy, message, param) \
do \
{ \
if (!(truthy)) \
{\
cout << message << " on line " << __LINE__ << " in file " << __FILE__ << ". Check was " << #truthy << ", value was " << param << endl;\
cout << g; \
} \
} while (0)
What you have currently means that this is valid code:
ASSERT(foo != 0)
else
{
}
And this is NOT valid code:
if (foo != nullptr)
ASSERT(foo->bar != nullptr);
else
x = 10;
Surprisingly, I solved a similar problem before, but I'm not sure if it could help you in this case.
The original solution was proposed by Andrei Alexandrescu in the article Enhancing Assertions, and with no question, relying on some macro tricks.
This amazing facility can be used as the following:
string s1, s2;
...
SMART_ASSERT(s1.empty() && s2.empty())(s1)(s2);
And if something goes wrong, the message would be displayed
Assertion failed in matrix.cpp: 879412:
Expression: 's1.empty() && s2.empty()'
Values: s1 = "Wake up, Neo"
s2 = "It's time to reload."
Be noted that, the SMART_ASSERT can capture infinite variables, theoretically.
For implementation details, please check out the article.
I would like to make single string from __FILE__, __FUNCTION__, and __LINE__ predefined macros.
#define LOG_LINE __FILE__ " " __FUNCTION__ " " __LINE__
This probably will don't work because compiler concat don't work with integers which __LINE__ is.
#define LOG_LINE __FILE__ __FUNCTION__
also don't work, because:
error: expected ';' before '__FUNCTION__'
How to achieve that to have
std::cout << LOG_LINE which will expand to e.g. main.cpp main 8?
Solution:
#define LOG_LINE __FILE__ << " " << __FUNCTION__ does not satisfy me because sometimes I would like to use it as string (big macro with sstream also is not valid solution ;).
You may use the following:
#define LOG_LINE (std::string(__FILE__ " ") + __FUNCTION__ + " " + std::to_string(__LINE__))
Live example
This is my assert function (it wont compile "error C2110: '+' : cannot add two pointers"):
#define CHAR(x) #x
template<typename T>
inline void ASSERT(T x)
{
if(!x)
{
std::string s("ERROR! Assert " + CHAR(x) + " failed. In file " + __FILE__ +
" at line " + __LINE__ + ".");
std::wstring temp(s.length(), L' ');
std::copy(s.begin(), s.end(), temp.begin());
getLogger().Write(temp);
}
}
Any idea of how to fix it?
String Literals are easily reduced to char pointers, which cannot be added as you try to do with "ERROR! Assert " + CHAR(x) + " failed. In file ".... However, C++ has the handy feature of doing this automatically before compilation! (the preprocessor does this). Even better, it has a handy tool for making wide strings at compile time. So, you want:
#define _T(x) L ## x
#define CHAR(x) #x
#define CHAR2(x) CHAR(x)
#define ASSERT(x) ASSERT2(x, CHAR(x), __FILE__, CHAR2(__LINE__))
#define ASSERT2(x, t, f, l) \
if(!x) \
getLogger().Write(L"ERROR! Assert " _T(t) L" failed. In file " _T(f) L" at line " _T(l) L".");
http://ideone.com/0ibcj
The compiler error is quite clear; you are trying to apply the + operator to string literals. A quick way to fix it is enclosing the first string literal in std::string().
As #James McNellis pointed out, note that FILE and LINE will point to the file and line of the assert function declaration.
You cannot use the + operator to concatenate two char*s; you need printf or some sort of thing for that.
"ERROR! Assert " is a null-terminated, C-style string. You can't execute operator+ on it.
A few issues:
Generally an assert should break into the debugger or dump if one is not attached. This will not.
As already mentioned, your LINE and FILE require use in a macro
You need a couple "helper" macros to get the strings working properly
Try something along these lines:
#define ASSERT_QUOTE_(x) #x
#define ASSERT_QUOTE_(x) ASSERT_QUOTE_(x)
#define MY_ASSERT(cond) \
if(cond) {} else { \
std::stringstream ss; \
ss << "ERROR! Assert " << ASSERT_QUOTE(cond) << " failed. In file " << __FILE__ << " at line " << __LINE__ << "."; \
getLogger().Write(ss.str()); \
}
Be careful trying to use STL here however. I suggest you have your logger's Write() function take variable arguments and process them with printf() or perhaps boost::format