Replace C macro for a function call with a C++ template? - c++

Is it possible to replace this preprocessor macro:
#define AL_CALL(a) do { a; \
ALenum e = alGetError(); \
if(e != AL_NO_ERROR) \
UtilitySoundNode::printALError(e,__FILE__, __LINE__); \
} while(0)
with a C++ template? If it is possible, will make any sense to do it (pros/cons - overhead/debugging)?
Note:
Basically I am wondering if there is an elegant way to handle this kind of error handling in C++.
EDIT:
Of course I made a mistake a is a function call. As one may guess it is a function call with parameters of a OpenAL function.
AL_CALL(someAlFunction(param1, param2))
NOTE:
Somebody decided to edit the macro and make it nicer but I'd prefer to keep the original one too. So here it is:
#define AL_CALL(a) {a; ALenum e = alGetError();if(e != AL_NO_ERROR)PUtilitySoundNode::printALError(e,__FILE__, __LINE__);}

One problem here seems to be that the "a" can be some arbitrary function (with parameters) which sets the error code returned by alGetError().
That can be rewritten to C++ by using a functor object. To pass the arguments (and object instance if necessary) std::bind or boost::bind can be used (note that to bind reference args the std::ref/boost::ref is necessary).
However, if you'd want to still have the __FILE__ and __LINE__ passed the the printError() that C++ template still would need to be called by a macro which will pass those to the template. __FILE__ and __LINE__ are only expanded by the preprocessor, so there is no way around using a macro for them.
But the macro could be much simpler then and most of the work can be done in the C++ template (which has many advantages e.g. for debugging, because in most debuggers you cannot step into a macro).
EDIT: adding the code as an example:
template<typename T>
void ALcallAndCheck(T c, const char *file, size_t line)
{
c();
ALenum e = alGetError();
if(e != AL_NO_ERROR)
UtilitySoundNode::printALError(e, file, line); \
}
#define AL_CALL(a) ALcallAndCheck(a, __FILE__, __LINE__)
Then, instead of
AL_CALL(SomeFunction(2, refAttr));
the call will become:
AL_CALL(std::bind(SomeFunction, 2, std::ref(refAttr)));
EDIT 2:
The previous indeed does not work with expressions, which the original macro allows. To work also for expressions, the macro can be altered to:
#define AL_CALL(a) ALcallAndCheck([&]{ (a); }, __FILE__, __LINE__)
That will create a lambda which will evaluate anything that comes into the macro. Then even the std::bind is not necessary and it can be called directly as:
AL_CALL(SomeFunction(2, refAttr));
AL_CALL(SomeOtherFunction1()+SomeOtherFunction2(8));

No, the use of __FILE__ and __LINE__ pretty well require the preprocessor.

Note that using a template instead of a macro does not produce an exact analog. The macro defined in your question allows a to represent a statement as well as an expression. A template does not have that kind of flexibility. The template defined below assumes a is a non-void expression.
There is no standard way to implicitly inject a function caller's file name and line number without the caller passing in that information to the called function. A preprocessor macro allows a means to make the syntax appear to be implicit injection, when in fact the information is being passed.
template <typename T>
void AL_CALL (T a, const char *file, int line) {
ALenum e = alGetError();
if(e != AL_NO_ERROR)
UtilitySoundNode::printALError(e, file, line);
}
#define AL_CALL(X) AL_CALL((X), __FILE__, __LINE__)
You may be able to use system specific facilities (e.g., CaptureStackBackTrace + SymFromAddr or backtrace + backtrace_symbols) to get approximately the same information implicitly, but it may require debugging symbols to be present, and inline functions may not produce the expected output.

template<class A>
void al_call(A&&a){
ALenum e = a();
if(e != AL_NO_ERROR)
UtilitySoundNode::printALError(e,__FILE__, __LINE__);
}
Use:
al_call( [&]{ return bob(); });
Instead of:
AL_CALL( bob() )
The line/file info is not useful above.
So
template<class A>
void al_call(A&&a, char const*file, unsigned line){
ALenum e = a();
if(e != AL_NO_ERROR)
UtilitySoundNode::printALError(e,file, line);
}
#define AL_CALL(...) al_call([&]()mutable{return __VA_ARGS__;}, __FILE__, __LINE__)
and it is almost a drop in replacement.

Related

Creating a custom printf with validation and syntax highlighting

I'd like to be able to create a logging mechanism, which very simply passes arguments through to printf, but I need syntax highlighting, and validation of input. This is the outline for the Log namespace I have so far.
#pragma once
#include "pch.h"
namespace Log
{
// Determines whether to create the console window or not.
// Turn off for before release.
extern bool CreateConsoleWindow;
// Initialisation.
extern bool Init();
// Writes a line to the console, appended with \r\n.
extern void WriteLine(const char* _Format, ...);
// Writes a line to the console, with a [Debug] prepend.
extern void DebugInfo(const char* _Format, ...);
// Writes a line to the console, with a [Server] prepend.
extern void ServerInfo(const char* _Format, ...);
// Destruction.
extern bool Dispose();
}
This is my implementation for Log::WriteLine(_Format, ...):
// Writes a line to the console, appended with \r\n.
void WriteLine(const char* _Format, ...)
{
// Print the message.
char buffer[4096];
va_list args;
va_start(args, _Format);
auto rc = vsnprintf(buffer, sizeof(buffer), _Format, args);
va_end(args);
// Append the new line.
printf("\r\n");
}
But when I do this, I lose all the validation and syntax highlighting, which is essential, being a beginner, from the input string. For instance:
auto hash = Crypto::GetHash(syntax[1].c_str()); // unsigned long, by way of multiple nested macros.
printf("Hash: %d", hash);
This would show %d in lime green, and there would be a warning on hash in the the printf, saying it won't be displayed, because it expects %lu. I rely on VS to teach me what I'm doing wrong, so that I can learn from my mistakes.
If I do the same with my function:
auto hash = Crypto::GetHash(syntax[1].c_str()); // unsigned long, by way of multiple nested macros.
Log::WriteLine("Hash: %d", hash);
Then %d is the same brown as the rest of the string, and there is no validation error.
These two things are essential. Is there any way to make this work properly? I'm new to C++ after about a decade of .NET experience, and the learning curve is massive. I thought I'd start with the basics, just an easy logging system, so I can see what is being output at any time, in a clean and elegant way. In C#, this would have only taken a couple of minutes to put together, but in C++, it's now four hours later, I have about 40 tabs open in three windows of Firefox, and I'm still smashing my head against every brick wall it's possible to come across.
I've tried to define a macro inside the namespace:
#define WriteLine(_Format, ...) printf(_Format, __VA_ARGS__)
But is says it can't find printf. I've tried decorating with _Printf_format_string_:
extern int _cdecl DebugInfo(_Printf_format_string_ const char* _Format, ...);
But that makes no difference. I've tried __attribute__((format(printf, 1, 2)))
extern void WriteLine(const char* _Format, ...) __attribute__((format(printf, 1, 2)));
But that throws up a mass of errors about expecting a {, unexpected identifier, and expected a declaration, but doesn't say where, or why, or how.
Am I asking too much of C++, for such a basic request?
Modern code editors and IDEs (and compilers!) provide additional support for the printf family of functions beyond the scope of the C++ and C languages. One prime example of that is extended error checking for the format strings, which cannot be done in C at all, and in C++ only with major pains. There are a few ways of achieving your aim with only minor modifications.
<iostreams> Solution
By default, std::cout is synchronized with printf, so you may not actually need to deal with printf directly. There are many solutions out there for how to achieve various results with the iostreams library framework, even though it is a bit of a hassle to use. It is type-safe, thus not requiring additional IDE support to directly show mistakes.
Note that iostreams has a rather bad reputation for its complexity and ease-of-use.
Typesafe Variadic Template
You can use a variadic template along the lines of:
void add_format_specifier(std::ostream& out, int const&) {
out << "%d";
}
void add_format_specifier(std::ostream& out, char const*) {
out << "%s";
}
void add_format_specifier(std::ostream& out, hex const&) {
out << "%x";
}
template<typename... Args>
void WriteLine(Args&&... args) {
std::ostringstream format;
((void)0, ..., add_format_specifier(format, args));
printf(format.str().c_str(), args...);
}
This solution is type-safe and compiler-checked, again without relying on special-casing printf. Personally, I would suggest going down this route, as it combines maximum flexibility with easy type-checking - and does away with the format specifier ;). You may wish to decide whether using printf as the low-level primitive is really what you want to do here, but it is easily exchanged for other methods of output.
Compile-Time Checking of a Format String
It is possible to add custom compile-time checking of format specifiers that you can then static_assert. The basic building blocks that you need is a variadic template that also takes your format specifier (basically, you need to preserve types inside your variadic function), and which calls a format specifier along the lines of:
template<std::size_t N>
consteval bool check_format(char const (&format)[N], std::size_t i) {
for(; i < N; ++i) {
if(format[i] == '%') {
if(i + 1 >= N) {
return false;
}
if(format[i + 1] == '%') {
++i; // skip literal '%'
} else {
return false; // no more specifiers expected
}
}
}
return true;
}
template<std::size_t N, typename T, typename... Args>
consteval bool check_format(char const (&format)[N], std::size_t i) {
for(; i < N; ++i) {
if(format[i] == '%') {
if(i + 1 >= N) {
return false; // unterminated format specifier
}
if(format[i + 1] == '%') {
++i; // skip literal '%'
} else {
if constexpr(std::is_same_v<T, int>) {
// quickly check if it is an acceptable integer format specifier
if(format[i + 1] != 'd' && format[i + 1] != 'x') {
return false;
} else {
return check_format<N, Args...>(format, i + 2);
}
} else {
return false; // unknown format specifier
}
}
}
}
return false;
}
See here for a bit more context. (Note: This example relies on the C++20 consteval specifier, which may not be supported by your compiler. Similar effects can be achieved with constexpr.)
This solution will give you compile-time errors, but no syntax highlighting - C++ cannot impact how your IDE draws strings (yet ;) ).
Macro Solution
While your macro #define WriteLine(_Format, ...) printf(_Format, __VA_ARGS__) does not really allow you to do all that much with respect to implementing anything beyond renaming printf, it will work, provided that the user code also include <cstdio>. If you provide a header with that macro, you may wish to just add the inclusion in there for ease of use.
There is only a tiny improvement to be made, so that the macro also works for calls of the form WriteLine("abc"):
#include <cstdio>
#define WriteLine(_Format, ...) printf(_Format __VA_OPT__(,) __VA_ARGS__)

Custom `assert` macro that supports commas and error message

I would like to create a custom version of the assert macro defined in <cassert>, that displays an error message when the assertion fails.
Desired usage:
custom_assert(AClass<T1, T2>::aBoolMethod(), "aBoolMethod must be true");
Flawed test implementations:
#define custom_assert(mCondition, mMessage) ...
// This fails because mCondition may have commas in it
#define custom_assert(..., mMessage)
// Not sure about this either - mMessage may be an expression containing commas
// as well
How can I correctly implement a custom assert that takes a boolean expression (with possible commas) as the first argument and a string expression (with possible commas) as the second argument?
Or is there a way to implement assertions without the use of macros?
You were quite close, what you need to use is simply this:
#define myAssert(message, ...) do { \
if(!(__VA_ARGS__)) { \
/*error code*/ \
} \
} while(0)
The special preprocessor variable __VA_ARGS__ will expand to whatever was passed in the place of the three dots, including all comas.
Note that the preprocessor will not interprete commas in the condition in the very least, it will just paste them as is into the if() statement. Which is precisely what you want if you want to pass templated conditions, as hinted by the comments.
Commas in the message string are not a problem either, since the preprocessor understands about string literals and does not interprete anything within the double quotes.
The straightforward
assert(AClass<T1, T2>::aBoolMethod() && "aBoolMethod must be true");
fails:
error: macro "assert" passed 2 arguments, but takes just 1
but if you add an extra pair of parenthesis around the first argument, it works. Like this:
#include <cassert>
template <typename A, typename B>
struct C {
bool f() { return false; }
};
int main() {
assert((C<int,int>().f()) && "some message, with comma");
// ^ ^
}
Note: it was also pointed out by Adam Rosenfield in a comment.
Perhaps the only benefit over the __VA_ARGS__ approach is that it doesn't dump yet another macro on the user. If you forget the parenthesis, you can get a compile time error, so I see it as a safe solution.
For the sake of completeness, I published a drop-in 2 files assert macro implementation in C++:
#include <pempek_assert.h>
int main()
{
float min = 0.0f;
float max = 1.0f;
float v = 2.0f;
PEMPEK_ASSERT(v > min && v < max,
"invalid value: %f, must be between %f and %f", v, min, max);
return 0;
}
Will prompt you with:
Assertion 'v > min && v < max' failed (DEBUG)
in file e.cpp, line 8
function: int main()
with message: invalid value: 2.000000, must be between 0.000000 and 1.000000
Press (I)gnore / Ignore (F)orever / Ignore (A)ll / (D)ebug / A(b)ort:
Where
(I)gnore: ignore the current assertion
Ignore (F)orever: remember the file and line where the assertion fired and
ignore it for the remaining execution of the program
Ignore (A)ll: ignore all remaining assertions (all files and lines)
(D)ebug: break into the debugger if attached, otherwise abort() (on Windows,
the system will prompt the user to attach a debugger)
A(b)ort: call abort() immediately
You can find out more about it there:
blog post
GitHub project
Hope that helps.
I'm not entirely sure what you mean by a "boolean expression with commas." Simply wrapping macro expansions in commas (as seen in the samples below) protects against parse errors if you happen to use the default comma operator in your conditions, but the default comma operator does not do the same thing as &&. If you mean you want something like:
my_assert(condition1, condition2, message1, message2);
You're out of luck. How should any API tell where the conditions stop and the messages start. Just use &&. You can use the same tricks below for handling the message portion to also create a my_condition_set macro that allows you to write something like:
my_asssert(my_condition_set(condition1, condition2), message1, message2);
Getting to the message part, which is the tricky part and the most useful part that the standard assert macros tend to lack, the trick will come down to either using a custom message output type that overrides operator, (the comma operator) or to use a variadic template.
The macro uses variadic macro support and some tricks to deal with commas. Note that none of the code I'm posting here is tested directly; it's all from memory from custom assert macros I've written in the past.
The version using comma operator overloading, which works in C++98 compilers:
struct logger {
template <typename T>
logger& operator,(const T& value) {
std::cerr << value;
return *this;
}
};
#define my_assert(condition, ...) do{ \
if (!(condition)) { \
(logger() , __VA_ARGS__); \
std::terminate(); \
} \
}while(false)
The logger() expression creates a new instance of the logger type. The list of arguments from __VA_ARGS__ is then pasted with commas separating each. These commas each invoke the comma operator left-to-right, which forwards the expression on to std::cerr. I usually use a custom log stream that handles writing to files, cerr, Windows' OutputDebugStringA, or whatever.
Using variadic templates in a C++11 compiler, this would be more like:
template <typename ...Ts>
void logger(Ts&&... argv) {
std::cerr << your_string_format_function(argv...);
}
void logger(const char* fmt) {
std::cerr << fmt;
}
void logger() {}
#define my_assert(condition, ...) do{ \
if (!(condition)) { \
logger(__VA_ARGS__); \
std::terminate(); \
} \
}while(false)
You'd need a format string function that actually works with variadic arguments or write an adapter for something like boost::format.
You could also use printf if you don't mind the lack of type-safety.

Deferring evaluation of function-call arguments

I wrote a small logging class that takes two or more arguments:
void my_log(int level, pattern [, fillins...]);
(The pattern and fill-ins are processed in a sprintf-like manner.)
The implementation of my_log begins:
if ( level < _min_level ) return;
I thought this would tidily short-circuit the call to very_elaborate_representation() ...
my_log(DEBUG, "%s", my_object.very_elaborate_representation());
when _min_level is greater than DEBUG.
But it doesn't: apparently (and not surprisingly) arguments are evaluated before the function call.
The formatting is expensive, and intended only for debugging and trouble-shooting.
Is there a clean way to solve this problem with C++11, other than wrapping the call with an if-test?
Not sure if it helps, but this is how I have previously implemented a logging module:
In the header file:
#define LOG(level,...) do {if (level >= MIN_LEVEL) log_printf(__VA_ARGS__);} while (0)
void log_printf(const char* data,...);
In the source file:
void log_printf(const char* data,...)
{
char str[64] = {0}; // You can think of other ways for allocating it
va_list args;
va_start(args,data);
vsnprintf(str,sizeof(str),data,args);
va_end(args);
printf(str);
}
In order to issue a log message, you only need to call LOG(SOME_LEVEL,some-parameters).

C++ macro expansion to function body

I would like to be able to write a macro CONDITIONALFUNCTION so that
CONDITIONALFUNCTION( FunctionName )
{
ConditionalExpression()
}
expands to
bool FunctionName( const Arguments& args )
{
return ConditionalExpression();
}
Is this even possible?
The closest I can find on SO is this thread:
Possible to define a function-like macro with a variable body?
except unlike in that thread, I have the additional requirement that the "body" within the braces is not a complete valid C++ statement, but rather an expression to be wrapped (effectively) in an 'if' statement.
Please assume I already know this may be impossible, and is almost surely stupid and evil :)
I'm going to assume you've got a good reason for using macros in the first place...
It's not possible with the syntax you've given with the question.
The closest workable macro syntax is:
#define CONDITIONALEXPRESSION(f, c) \
bool f( const Arguments& args ) \
{ return c; }
CONDITIONALEXPRESSION(FunctionName, ConditionalExpression())
This will expand to the same as the expanded function in the question
Is there any reason why the function body must be defined in the macro? In Microsoft C++, macros like ASSERT() define the actual function separately and then just reference it from the macro.
So the function is always defined but the macro is either equal to calling the function or nothing at all.
Aside from that, for C++ I'd probably use an inline function.
je4d already provided one alternative. I over some other variation:
#define CONDITIONALEXPRESSION(f) \
bool f( const Arguments& args )
#define CONDITIONALRETURN(c) \
return (c)
CONDITIONALEXPRESSION(FunctionName)
{
CONDITIONALRETURN(ConditionalExpression())
}

How can one make a 'passthru' function in C++ using macros or metaprogramming?

So I have a series of global functions, say:
foo_f1(int a, int b, char *c);
foo_f2(int a);
foo_f3(char *a);
I want to make a C++ wrapper around these, something like:
MyFoo::f1(int a, int b, char* c);
MyFoo::f2(int a);
MyFoo::f3(char* a);
There's about 40 functions like this, 35 of them I just want to pass through to the global function, the other 5 I want to do something different with.
Ideally the implementation of MyFoo.cpp would be something like:
PASSTHRU( f1, (int a, int b, char *c) );
PASSTHRU( f2, (int a) );
MyFoo::f3(char *a)
{
//do my own thing here
}
But I'm having trouble figuring out an elegant way to make the above PASSTHRU macro.
What I really need is something like the mythical X getArgs() below:
MyFoo::f1(int a, int b, char *c)
{
X args = getArgs();
args++; //skip past implicit this..
::f1(args); //pass args to global function
}
But short of dropping into assembly I can't find a good implementation of getArgs().
You could use Boost.Preprocessor to let the following:
struct X {
PASSTHRU(foo, void, (int)(char))
};
... expand to:
struct X {
void foo ( int arg0 , char arg1 ) { return ::foo ( arg0 , arg1 ); }
};
... using these macros:
#define DO_MAKE_ARGS(r, data, i, type) \
BOOST_PP_COMMA_IF(i) type arg##i
#define PASSTHRU(name, ret, args) \
ret name ( \
BOOST_PP_SEQ_FOR_EACH_I(DO_MAKE_ARGS, _, args) \
) { \
return ::name ( \
BOOST_PP_ENUM_PARAMS(BOOST_PP_SEQ_SIZE(args), arg) \
); \
}
At 40-odd functions, you could type the wrappers out by hand in an hour. The compiler will check the correctness of the result. Assume an extra 2 minutes for each new function that needs wrapping, and an extra 1 minute for a change in signature.
As specified, and with no mention of frequent updates or changes, it doesn't sound like this problem requires a cunning solution.
So, my recommendation is to keep it simple: do it by hand. Copy prototypes into source file, then use keyboard macros (emacs/Visual Studio/vim) to fix things up, and/or multiple passes of search and replace, generating one set of definitions and one set of declarations. Cut declarations, paste into header. Fill in definitions for the non-passing-through functions. This won't win you any awards, but it'll be over soon enough.
No extra dependencies, no new build tools, works well with code browsing/tags/intellisense/etc., works well with any debugger, and no specialized syntax/modern features/templates/etc., so anybody can understand the result. (It's true that nobody will be impressed -- but it will be the good kind of unimpressed.)
Slightly different syntax but...
#include <boost/preprocessor.hpp>
#include <iostream>
void f1(int x, int y, char* z) { std::cout << "::f1(int,int,char*)\n"; }
#define GENERATE_ARG(z,n,unused) BOOST_PP_CAT(arg,n)
#define GET_ARGS(n) BOOST_PP_ENUM(n, GENERATE_ARG, ~)
#define GENERATE_PARAM(z,n,seq) BOOST_PP_SEQ_ELEM(n,seq) GENERATE_ARG(z,n,~)
#define GENERATE_PARAMS(seq) BOOST_PP_ENUM( BOOST_PP_SEQ_SIZE(seq), GENERATE_PARAM, seq )
#define PASSTHROUGH(Classname, Function, ArgTypeSeq) \
void Classname::Function( GENERATE_PARAMS(ArgTypeSeq) ) \
{ \
::Function( GET_ARGS( BOOST_PP_SEQ_SIZE(ArgTypeSeq) ) ); \
}
struct test
{
void f1(int,int,char*);
};
PASSTHROUGH(test,f1,(int)(int)(char*))
int main()
{
test().f1(5,5,0);
std::cin.get();
}
You could get something closer to yours if you use tuples, but you'd have to supply the arg count to the base function (you can't derive a size from a tuple). Sort of like so:
PASSTHROUGH(test,f1,3,(int,int,char*))
That about what you're looking for? I knew it could be done; took about a half hour to solve. You seem to expect that there's an implicit 'this' that has to be gotten rid of but I don't see why...so maybe I misunderstand the problem. At any rate, this will let you quickly make default "passthrough" member functions that defer to some global function. You'll need a DECPASSTHROUGH for the class declaration if you want to skip having to declare them all...or you could modify this to make inline functions.
Hint: Use BOOST_PP_STRINGIZE((XX)) to test the output of preprocessor metafunctions.
My initial thought, and this probably won't work or others would have stated this, is to put all your base functions together in a class as virtual. Then, write the functionality improvements into inherited classes and run with it. It's not a macro wrapper, but you could always call the global functions in the virtual classes.
With some assembly trickery, you could probably do exactly what you'd want, but you would lose portability more than likely. Interesting question and I want to hear other's answers as well.
You may want to use a namespace if you want to not deal with class stuff, like this. You could also use static member methods in a class, but I think that people don't like that anymore.
#ifndef __cplusplus
#define PASSTHRU(type, prefix, func, args) type prefix##_##func args
#else
#define PASSTHRU(type, prefix, func, args) type prefix::func args
#endif
Or
#ifndef __cplusplus
#define PASSTHRU(type, prefix, func, ...) type prefix##_##func(__VA_ARGS__)
...
Perfect forwarding relies on rvalue references. STL has a blog entry on it at Link and you would want to choose a compiler that supported the feature to take this approach. He's discussing Visual C++ 2010.