Related
Say I have a macro like this:
#define SET_TYPE_NAME(TYPE, NAME) \
template<typename T> \
std::string name(); \
\
template<> \
std::string name<TYPE>() { \
return NAME; \
}
This won't work if I pass it a template that has more than one parameter, because the comma in the <int, int> is interpreted as separating the macro arguments, not the template arguments.
SET_TYPE_NAME(std::map<int, int>, "TheMap")
// Error: macro expects two arguments, three given
This problem seems to be solved by doing this:
SET_TYPE_NAME((std::map<int, int>), "TheMap")
But now another problem arises, one that I really did not expect:
template<>
std::string name<(std::map<int, int>)>()
// template argument 1 is invalid
It seems that the extra parentheses make the template argument invalid. Is there any way around this?
Besides typedef, you could switch the order of the arguments and use variadic macros (requires C99 or C++11-compatible compiler):
#define SET_TYPE_NAME(NAME, ...) \
template<typename T> \
std::string name(); \
\
template<> \
std::string name<__VA_ARGS__>() { \
return NAME; \
}
...
SET_TYPE_NAME("TheMap", std::map<int, int>)
You could use typedef:
typedef std::map<int, int> int_map;
SET_TYPE_NAME(int_map, "TheMap");
boost's BOOST_FOREACH suffers from the same issue.
Some time ago (while searching the web for the utility of Identity<T>) I got to this page.
In brief, to answer the question, if you don't have C++11 support and/or can't (or don't want to) use a typedef, you call your macro the "right" way:
// If an argument contains commas, enclose it in parentheses:
SET_TYPE_NAME((std::map<int, int>), "TheMap")
// For an argument that doesn't contain commas, both should work:
SET_TYPE_NAME((SomeType1), "TheType1")
SET_TYPE_NAME(SomeType2, "TheType2")
and then to get rid of the (possible) unwanted parentheses around the type, you can use a "helper" like this:
template<typename> struct RemoveBrackets;
template<typename T> struct RemoveBrackets<void (T)> {
typedef T Type;
};
and in your macro change the line:
std::string name<TYPE>() { \
to:
std::string name< RemoveBrackets<void (TYPE)>::Type >() { \
(or define a helper macro, say
#define REMOVE_BRACKETS(x) RemoveBrackets<void (x)>::Type
then replace the line with
std::string name< REMOVE_BRACKETS(TYPE) >() { \
).
(For the full story read the paragraph "An even better solution" at the end of the article linked above.)
Edit: just found that. But it uses <void X> when it really should use <void (X)> (in get_first_param<void X>::type); indeed the parentheses are necessary if you pass a "simple", non-bracketed argument (like SomeType2 in my code above) -- and they don't hurt if X is already bracketed (e.g., void ((SomeType1)) is equivalent to void (SomeType1); again, see the article). (By the way, I noticed that many answers on the other SO page are in essence "Macros are dumb". I won't comment, though.)
I'd like to add an answer to my own question. Now that Boost 1.50.0 was released, Boost.Utility has a new mini-library that helps with this kind of thing. If you look at the source you'll see it's implemented the same as gx_'s solution. Here's how to use it:
#include <boost/utility/identity_type.hpp>
SET_TYPE_NAME(BOOST_IDENTITY_TYPE((std::map<int, int>)), "TheMap");
http://www.boost.org/doc/libs/1_50_0/libs/utility/identity_type/doc/html/index.html
I like the typedef way proposed by hmjd better, but for the record, the usual way I've seen around this is to kick the angle brackets out of the macro and write:
#define SET_TYPE_NAME(TYPE, NAME) \
template<typename T> \
std::string name(); \
\
template<> \
std::string name TYPE() { \
return NAME; \
}
Usage:
SET_TYPE_NAME(<std::map<int, int> >, "TheMap")
This is a variation of an old technique used for error message reporting and fprintf:
#define Error(args) do { \
printf("ERROR: "); \
printf args; \
printf("\n"); \
return 1; \
} while(0)
Called with:
Error(("Index out of range: %d not in %d ... %d.", var, min, max));
It's ugly but it worked. Useful if the coding style rules ban typedef.
typedef std::map<int,int> IntMap_t;
SET_TYPE_NAME(IntMap_t, "TheMap")
You can declare a typedef and use it in the macro
A more generic way is to always use () around your arguments that may contain a comma and use CONCAT to remove the parenthesis. If you do so, you can define multiple parameters packs wits comma inside or put arguments in your favorite order
#ifndef CONCAT
#define CONCAT __VA_ARGS__
#endif
#define MYMACRO(tparam,classname)\
template < CONCAT tparam >\
class CONCAT classname {};
//create a template class X<T,U>
MYMACRO( (typename T,typename U) , (X<T,U>) )
I know this is an old question. Though this comes in top results on a Google search and nobody has yet mentioned an even more simple solution by defining a macro for the comma:
#define COMMA ,
SET_TYPE_NAME(std::map<int COMMA int>, "TheMap")
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.
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())
}
Say I have a macro like this:
#define SET_TYPE_NAME(TYPE, NAME) \
template<typename T> \
std::string name(); \
\
template<> \
std::string name<TYPE>() { \
return NAME; \
}
This won't work if I pass it a template that has more than one parameter, because the comma in the <int, int> is interpreted as separating the macro arguments, not the template arguments.
SET_TYPE_NAME(std::map<int, int>, "TheMap")
// Error: macro expects two arguments, three given
This problem seems to be solved by doing this:
SET_TYPE_NAME((std::map<int, int>), "TheMap")
But now another problem arises, one that I really did not expect:
template<>
std::string name<(std::map<int, int>)>()
// template argument 1 is invalid
It seems that the extra parentheses make the template argument invalid. Is there any way around this?
Besides typedef, you could switch the order of the arguments and use variadic macros (requires C99 or C++11-compatible compiler):
#define SET_TYPE_NAME(NAME, ...) \
template<typename T> \
std::string name(); \
\
template<> \
std::string name<__VA_ARGS__>() { \
return NAME; \
}
...
SET_TYPE_NAME("TheMap", std::map<int, int>)
You could use typedef:
typedef std::map<int, int> int_map;
SET_TYPE_NAME(int_map, "TheMap");
boost's BOOST_FOREACH suffers from the same issue.
Some time ago (while searching the web for the utility of Identity<T>) I got to this page.
In brief, to answer the question, if you don't have C++11 support and/or can't (or don't want to) use a typedef, you call your macro the "right" way:
// If an argument contains commas, enclose it in parentheses:
SET_TYPE_NAME((std::map<int, int>), "TheMap")
// For an argument that doesn't contain commas, both should work:
SET_TYPE_NAME((SomeType1), "TheType1")
SET_TYPE_NAME(SomeType2, "TheType2")
and then to get rid of the (possible) unwanted parentheses around the type, you can use a "helper" like this:
template<typename> struct RemoveBrackets;
template<typename T> struct RemoveBrackets<void (T)> {
typedef T Type;
};
and in your macro change the line:
std::string name<TYPE>() { \
to:
std::string name< RemoveBrackets<void (TYPE)>::Type >() { \
(or define a helper macro, say
#define REMOVE_BRACKETS(x) RemoveBrackets<void (x)>::Type
then replace the line with
std::string name< REMOVE_BRACKETS(TYPE) >() { \
).
(For the full story read the paragraph "An even better solution" at the end of the article linked above.)
Edit: just found that. But it uses <void X> when it really should use <void (X)> (in get_first_param<void X>::type); indeed the parentheses are necessary if you pass a "simple", non-bracketed argument (like SomeType2 in my code above) -- and they don't hurt if X is already bracketed (e.g., void ((SomeType1)) is equivalent to void (SomeType1); again, see the article). (By the way, I noticed that many answers on the other SO page are in essence "Macros are dumb". I won't comment, though.)
I'd like to add an answer to my own question. Now that Boost 1.50.0 was released, Boost.Utility has a new mini-library that helps with this kind of thing. If you look at the source you'll see it's implemented the same as gx_'s solution. Here's how to use it:
#include <boost/utility/identity_type.hpp>
SET_TYPE_NAME(BOOST_IDENTITY_TYPE((std::map<int, int>)), "TheMap");
http://www.boost.org/doc/libs/1_50_0/libs/utility/identity_type/doc/html/index.html
I like the typedef way proposed by hmjd better, but for the record, the usual way I've seen around this is to kick the angle brackets out of the macro and write:
#define SET_TYPE_NAME(TYPE, NAME) \
template<typename T> \
std::string name(); \
\
template<> \
std::string name TYPE() { \
return NAME; \
}
Usage:
SET_TYPE_NAME(<std::map<int, int> >, "TheMap")
This is a variation of an old technique used for error message reporting and fprintf:
#define Error(args) do { \
printf("ERROR: "); \
printf args; \
printf("\n"); \
return 1; \
} while(0)
Called with:
Error(("Index out of range: %d not in %d ... %d.", var, min, max));
It's ugly but it worked. Useful if the coding style rules ban typedef.
typedef std::map<int,int> IntMap_t;
SET_TYPE_NAME(IntMap_t, "TheMap")
You can declare a typedef and use it in the macro
A more generic way is to always use () around your arguments that may contain a comma and use CONCAT to remove the parenthesis. If you do so, you can define multiple parameters packs wits comma inside or put arguments in your favorite order
#ifndef CONCAT
#define CONCAT __VA_ARGS__
#endif
#define MYMACRO(tparam,classname)\
template < CONCAT tparam >\
class CONCAT classname {};
//create a template class X<T,U>
MYMACRO( (typename T,typename U) , (X<T,U>) )
I know this is an old question. Though this comes in top results on a Google search and nobody has yet mentioned an even more simple solution by defining a macro for the comma:
#define COMMA ,
SET_TYPE_NAME(std::map<int COMMA int>, "TheMap")
Suppose I have a C++ macro CATCH to replace the catch statement and that macro receive as parameter a variable-declaration regular expression, like <type_name> [*] <var_name> or something like that. Is there a way to recognize those "fields" and use them in the macro definition?
For instance:
#define CATCH(var_declaration) <var_type> <var_name> = (<var_type>) exception_object;
Would work just like:
#define CATCH(var_type, var_name) var_type var_name = (var_type) exception_object;
As questioned, I'm using g++.
You can't do it with just macros, but you can be clever with some helper code.
template<typename ExceptionObjectType>
struct ExceptionObjectWrapper {
ExceptionObjectType& m_unwrapped;
ExceptionObjectWrapper(ExceptionObjectType& unwrapped)
: m_unwrapped(unwrapped) {}
template<typename CastType>
operator CastType() { return (CastType)m_wrapped; }
};
template<typename T>
ExceptionObjectWrapper<T> make_execption_obj_wrapper(T& eobj) {
return ExceptionObjectWrapper<T>(eobj);
}
#define CATCH(var_decl) var_decl = make_exception_obj_wrapper(exception_object);
With these definitions,
CATCH(Foo ex);
should work. I will admit to laziness in not testing this (in my defence, I don't have your exception object test with). If exception_object can only be one type, you can get rid of the ExceptionObjectType template parameter. Further more, if you can define the cast operators on the exception_object itself you can remove the wrappers altogether. I'm guessing exception_object is actually a void* or something though and your casting pointers.
What compiler are you using? I've never seen this done in the gcc preprocessor, but I can't say for sure that no preprocessor out there can implement this functionality.
What you could do however is run your script through something like sed to do your prepreprocessing so to speak before the preprocessor kicks in.
Hmmm... I'm just guessing, but why don't you try something like this : :)
#define CATCH(varType,varName) catch(varType& varName) { /* some code here */ }