
I've not had much opportunity to do much template metaprogramming in my work, but I've kept up with my reading. So, might I get some advice on how to approach this problem? I'm thinking of an assert-like statement that follows the syntax of Boost.Format, thus avoiding the variadic argument list. MY_FANCY_ASSERT (cond, "format string") % arg % arg; works if the macro expands to an unnamed temporary, whose destructor does the interesting work if the first argument is false. my_assert_formatter_type (cond, "cond", __FILE__, __LINE__, "format string") This is easy to do, simply deriving from boost::formatter, I would think. But, I want to avoid doing any work except on failure. This means remembering the arguments including the following %arg stuff, and passing everything through to Boost.Format based on the condition. So I'm thinking that template metaprogramming can let me collect all the arguments (any number of them) into one object, efficiently at compile time. So, what approach should I use? Plain MPL and classic metaprogramming? Fusion? Phoenix? and any concrete suggestions on how to proceed, or pointers to similar works? Thanks, —John

On Thu, 9 Feb 2012, John M. Dlugosz wrote:
I've not had much opportunity to do much template metaprogramming in my work, but I've kept up with my reading. So, might I get some advice on how to approach this problem?
I'm thinking of an assert-like statement that follows the syntax of Boost.Format, thus avoiding the variadic argument list.
MY_FANCY_ASSERT (cond, "format string") % arg % arg;
works if the macro expands to an unnamed temporary, whose destructor does the interesting work if the first argument is false.
Would it be reasonable for your use case to have MY_FANCY_ASSERT be: #define MY_FANCY_ASSERT(cond, str) \ if (cond) {} else format(str) % __FILE__ % __LINE__ or similar? It would restrict where you could use it, but would be simple and guarantee the properties you want. -- Jeremiah Willcock

On 2/9/2012 12:21 AM, Jeremiah Willcock wrote:
Would it be reasonable for your use case to have MY_FANCY_ASSERT be:
#define MY_FANCY_ASSERT(cond, str) \ if (cond) {} else format(str) % __FILE__ % __LINE__
or similar? It would restrict where you could use it, but would be simple and guarantee the properties you want.
Actually, that's not at all too unreasonable. I had shied away from making a macro that "eats" the following arguments in a non-expression way, on general principles. But I see that what you have doesn't leave a dangling-else problem, and I suppose people won't notice that it's at all funny. The auto-supplied arguments (FILE, LINE, etc. and the plain text of "cond" are not considered for in the format string. So the statement will be somewhat more complex, and of course take care of sending the resulting string on its way. I like the idea. Thanks. I'll think about that some more. —John

On Feb 9, 2012, at 1:47 AM, John M. Dlugosz wrote:
On 2/9/2012 12:21 AM, Jeremiah Willcock wrote:
Would it be reasonable for your use case to have MY_FANCY_ASSERT be:
#define MY_FANCY_ASSERT(cond, str) \ if (cond) {} else format(str) % __FILE__ % __LINE__
or similar? It would restrict where you could use it, but would be simple and guarantee the properties you want.
Actually, that's not at all too unreasonable. I had shied away from making a macro that "eats" the following arguments in a non-expression way, on general principles. But I see that what you have doesn't leave a dangling-else problem, and I suppose people won't notice that it's at all funny.
I have a similar macro and just yesterday received a bug report from one of my users because code like this if (cond1) MY_FANCY_ASSERT(cond2, ...) ... ; was resulting in compiler warnings from gcc: -Wparentheses (enabled by -Wall) complains about potential confusion over which "if" an "else" belongs to. I was unable to find a way to suppress the warning locally to the macro, even with the local diagnostic control pragmas available in gcc4.6 (though it might be argued that some of what I was seeing should be considered gcc bugs (I intend to file a bug report), so it might be that some future version of gcc will provide sufficient warning control for this situation). The workarounds are, of course, to move cond1 into the macro's conditional or to put braces around the whole outer "then" statement. Note that in nearly 3 years of heavy use of our facility that uses this idiom, this is the first time this issue has come up. So I wouldn't let this annoying warning stop you from taking this approach, just be warned (no pun intended) that there is this minor issue.

On Thu, 9 Feb 2012, Kim Barrett wrote:
On Feb 9, 2012, at 1:47 AM, John M. Dlugosz wrote:
On 2/9/2012 12:21 AM, Jeremiah Willcock wrote:
Would it be reasonable for your use case to have MY_FANCY_ASSERT be:
#define MY_FANCY_ASSERT(cond, str) \ if (cond) {} else format(str) % __FILE__ % __LINE__
or similar? It would restrict where you could use it, but would be simple and guarantee the properties you want.
Actually, that's not at all too unreasonable. I had shied away from making a macro that "eats" the following arguments in a non-expression way, on general principles. But I see that what you have doesn't leave a dangling-else problem, and I suppose people won't notice that it's at all funny.
I have a similar macro and just yesterday received a bug report from one of my users because code like this
if (cond1) MY_FANCY_ASSERT(cond2, ...) ... ;
was resulting in compiler warnings from gcc: -Wparentheses (enabled by -Wall) complains about potential confusion over which "if" an "else" belongs to. I was unable to find a way to suppress the warning locally to the macro, even with the local diagnostic control pragmas available in gcc4.6 (though it might be argued that some of what I was seeing should be considered gcc bugs (I intend to file a bug report), so it might be that some future version of gcc will provide sufficient warning control for this situation). The workarounds are, of course, to move cond1 into the macro's conditional or to put braces around the whole outer "then" statement.
Here's a variant that might work better for that: #define MY_FANCY_ASSERT(cond, str) \ for (bool BOOST_PP_CAT(assertcond, __LINE__) = (cond); \ BOOST_PP_CAT(assertcond, __LINE__); \ BOOST_PP_CAT(assertcond, __LINE__) = false) \ format(str) % __FILE__ % __LINE__ -- Jeremiah Willcock

On Feb 9, 2012, at 6:04 PM, Jeremiah Willcock wrote:
Here's a variant that might work better for that:
#define MY_FANCY_ASSERT(cond, str) \ for (bool BOOST_PP_CAT(assertcond, __LINE__) = (cond); \ BOOST_PP_CAT(assertcond, __LINE__); \ BOOST_PP_CAT(assertcond, __LINE__) = false) \ format(str) % __FILE__ % __LINE__
I'd forgotten about that trick. Thank you.

On 02/09/2012 10:29 PM, Kim Barrett wrote:
On Feb 9, 2012, at 1:47 AM, John M. Dlugosz wrote:
On 2/9/2012 12:21 AM, Jeremiah Willcock wrote:
Would it be reasonable for your use case to have MY_FANCY_ASSERT be:
#define MY_FANCY_ASSERT(cond, str) \ if (cond) {} else format(str) % __FILE__ % __LINE__
or similar? It would restrict where you could use it, but would be simple and guarantee the properties you want.
Actually, that's not at all too unreasonable. I had shied away from making a macro that "eats" the following arguments in a non-expression way, on general principles. But I see that what you have doesn't leave a dangling-else problem, and I suppose people won't notice that it's at all funny.
I have a similar macro and just yesterday received a bug report from one of my users because code like this
if (cond1) MY_FANCY_ASSERT(cond2, ...) ... ;
was resulting in compiler warnings from gcc: -Wparentheses (enabled by -Wall) complains about potential confusion over which "if" an "else" belongs to. I was unable to find a way to suppress the warning locally to the macro, even with the local diagnostic control pragmas available in gcc4.6 (though it might be argued that some of what I was seeing should be considered gcc bugs (I intend to file a bug report), so it might be that some future version of gcc will provide sufficient warning control for this situation). The workarounds are, of course, to move cond1 into the macro's conditional or to put braces around the whole outer "then" statement. That is not a bug of gcc. It is right if it states that the interpretation could be done in two way either the else belongs to the first if or to the second one. However, you can make yourself and the compiler happy. Try the following.
#define MY_FANCY_ASSERT(cond, str) \ do { if (cond) {} else format(str) % __FILE__ % __LINE__ } while(0) With this you have encapsulated the if-else statement and the compiler has now no reasons to complain anymore. -- Michael
Note that in nearly 3 years of heavy use of our facility that uses this idiom, this is the first time this issue has come up. So I wouldn't let this annoying warning stop you from taking this approach, just be warned (no pun intended) that there is this minor issue.
_______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users

On Feb 10, 2012, at 2:46 PM, Michael Schulze wrote:
That is not a bug of gcc. It is right if it states that the interpretation could be done in two way either the else belongs to the first if or to the second one. However, you can make yourself and the compiler happy. Try the following.
#define MY_FANCY_ASSERT(cond, str) \ do { if (cond) {} else format(str) % __FILE__ % __LINE__ } while(0)
With this you have encapsulated the if-else statement and the compiler has now no reasons to complain anymore.
I think you missed the point of all this. The macro is intended to be followed by user code to add stuff to the output, e.g. MY_FANCY_ASSERT(pred, str) % value1 % value2; The above suggestion prevents that. I'm quite familiar with that do/while(0); it's just not what's needed in this case. The potential gcc bugs I mentioned had nothing to do with the warning itself, but rather with my inability to use existing (in recent versions at least) mechanisms for locally disabling the warning. I think inserting appropriate _Pragma forms into the macro expansion should have worked but didn't.

On 2/10/2012 1:46 PM, Michael Schulze wrote:
That is not a bug of gcc. It is right if it states that the interpretation could be done in two way either the else belongs to the first if or to the second one. However, you can make yourself and the compiler happy. Try the following.
#define MY_FANCY_ASSERT(cond, str) \ do { if (cond) {} else format(str) % __FILE__ % __LINE__ } while(0)
With this you have encapsulated the if-else statement and the compiler has now no reasons to complain anymore.
How is that different from leaving off the do and while and just putting braces around the whole thing?
#define MY_FANCY_ASSERT(cond, str) \ { if (cond) {} else format(str) % __FILE__ % __LINE__ }

On Sat, 11 Feb 2012, John M. Dlugosz wrote:
On 2/10/2012 1:46 PM, Michael Schulze wrote:
That is not a bug of gcc. It is right if it states that the interpretation could be done in two way either the else belongs to the first if or to the second one. However, you can make yourself and the compiler happy. Try the following.
#define MY_FANCY_ASSERT(cond, str) \ do { if (cond) {} else format(str) % __FILE__ % __LINE__ } while(0)
With this you have encapsulated the if-else statement and the compiler has now no reasons to complain anymore.
How is that different from leaving off the do and while and just putting braces around the whole thing?
#define MY_FANCY_ASSERT(cond, str) \ { if (cond) {} else format(str) % __FILE__ % __LINE__ }
The do-while formulation requires the user to provide a semicolon after the macro call, while a normal set of braces does not. The do-while also fixes problems such as: if (p) MY_FANCY_ASSERT(...); else bar(); which is a syntax error since the first semicolon terminates the if statement, preventing the presence of an else clause later. -- Jeremiah Willcock

on Thu Feb 09 2012, Kim Barrett
On Feb 9, 2012, at 1:47 AM, John M. Dlugosz wrote:
On 2/9/2012 12:21 AM, Jeremiah Willcock wrote:
Would it be reasonable for your use case to have MY_FANCY_ASSERT be:
#define MY_FANCY_ASSERT(cond, str) \ if (cond) {} else format(str) % __FILE__ % __LINE__
or similar? It would restrict where you could use it, but would be simple and guarantee the properties you want.
Actually, that's not at all too unreasonable. I had shied away from making a macro that "eats" the following arguments in a non-expression way, on general principles. But I see that what you have doesn't leave a dangling-else problem, and I suppose people won't notice that it's at all funny.
I have a similar macro and just yesterday received a bug report from one of my users because code like this
if (cond1) MY_FANCY_ASSERT(cond2, ...) ... ;
was resulting in compiler warnings from gcc: -Wparentheses (enabled by -Wall) complains about potential confusion over which "if" an "else" belongs to. I was unable to find a way to suppress the warning locally to the macro, even with the local diagnostic control pragmas available in gcc4.6 (though it might be argued that some of what I was seeing should be considered gcc bugs (I intend to file a bug report)
Any old-timey C programmer will tell you the trick is to put your code inside a do { ... } while(0): #define MY_FANCY_ASSERT(cond, str) do { \ if (cond) {} else format(str) % __FILE__ % __LINE__ \ } while(0) Cheers, -- Dave Abrahams BoostPro Computing http://www.boostpro.com

On 2/9/2012 12:21 AM, Jeremiah Willcock wrote:
Would it be reasonable for your use case to have MY_FANCY_ASSERT be:
#define MY_FANCY_ASSERT(cond, str) \ if (cond) {} else format(str) % __FILE__ % __LINE__
or similar? It would restrict where you could use it, but would be simple and guarantee the properties you want.
I think suitable tricks, as being mentioned elsewhere on this thread, will make that kind of thing work just fine for my needs. The only issue is that I don't have anything inserted _after_ the %args. In particular, I can't put a try/catch around them. Boost.Format throws exceptions if the arguments are not good, and since this is for error message generation I want it to be fault-tolerant. Really, what I want is to make the format more tolerant, and then this will work just fine. I'll start a new thread on that. —John

On Thu, Feb 9, 2012 at 1:13 AM, John M. Dlugosz
work, but I've kept up with my reading. So, might I get some advice on how to approach this problem?
I'm thinking of an assert-like statement that follows the syntax of Boost.Format, thus avoiding the variadic argument list.
But, I want to avoid doing any work except on failure. This means remembering the arguments including the following %arg stuff, and passing everything through to Boost.Format based on the condition.
This isn't metaprogramming -- or at least not new metaprogramming, rather taking advantage of an existing library -- but my colleague came up with what I consider a clever use of Boost.Lambda for a similar sort of problem. We wanted a macro with usage of the form: OURMACRO("some streaming expr " << value << ...); that would stream arbitrary objects as in: hidden_ostream_object << "some streaming expr " << value << ...; His solution is like this: template <typename FUNCTOR> void ourmacro_f(const FUNCTOR& f) { f(hidden_ostream_object); } #define OURMACRO(EXPRESSION) (ourmacro_f(boost::lambda::_1 << EXPRESSION))
So, what approach should I use? Plain MPL and classic metaprogramming? Fusion? Phoenix?
In this case I guess Phoenix would be the way to go rather than Boost.Lambda.

On 2/9/2012 1:49 PM, Nat Linden wrote:
OURMACRO("some streaming expr " << value << ...);
that would stream arbitrary objects as in:
hidden_ostream_object << "some streaming expr " << value << ...;
His solution is like this:
template <typename FUNCTOR> void ourmacro_f(const FUNCTOR& f) { f(hidden_ostream_object); }
#define OURMACRO(EXPRESSION) (ourmacro_f(boost::lambda::_1 << EXPRESSION))\
How is that different from just using: #define OURMACRO(EXPRESSION) hidden_stream_object << EXPRESSION

On Thu, Feb 9, 2012 at 11:05 PM, John M. Dlugosz
On 2/9/2012 1:49 PM, Nat Linden wrote:
template <typename FUNCTOR> void ourmacro_f(const FUNCTOR& f) { f(hidden_ostream_object); }
#define OURMACRO(EXPRESSION) (ourmacro_f(boost::lambda::_1 << EXPRESSION))
How is that different from just using:
#define OURMACRO(EXPRESSION) hidden_stream_object << EXPRESSION
Simply that hidden_stream_object really isn't visible in the calling context. It's local to the context of ourmacro_f().

On 2/10/2012 7:35 AM, Nat Linden wrote:
On Thu, Feb 9, 2012 at 11:05 PM, John M. Dlugosz
wrote: On 2/9/2012 1:49 PM, Nat Linden wrote:
template<typename FUNCTOR> void ourmacro_f(const FUNCTOR& f) { f(hidden_ostream_object); }
#define OURMACRO(EXPRESSION) (ourmacro_f(boost::lambda::_1<< EXPRESSION))
How is that different from just using:
#define OURMACRO(EXPRESSION) hidden_stream_object<< EXPRESSION
Simply that hidden_stream_object really isn't visible in the calling context. It's local to the context of ourmacro_f().
Sorry, I'm still not seeing the point. The name hidden_stream_object is not in scope here but ourmacro_f is instead? So what? Or, a plain function to return the stream object? ostream& get_stream() { return hidden_stream_object; } #define OURMACRO(EXPRESSION) get_stream()<< EXPRESSION

On Sat, Feb 11, 2012 at 2:23 AM, John M. Dlugosz
On Thu, Feb 9, 2012 at 11:05 PM, John M. Dlugosz
wrote: On 2/9/2012 1:49 PM, Nat Linden wrote:
template<typename FUNCTOR>
void ourmacro_f(const FUNCTOR& f) { f(hidden_ostream_object); }
#define OURMACRO(EXPRESSION) (ourmacro_f(boost::lambda::_1<**< EXPRESSION))
How is that different from just using:
#define OURMACRO(EXPRESSION) hidden_stream_object<< EXPRESSION
Simply that hidden_stream_object really isn't visible in the calling context. It's local to the context of ourmacro_f().
Sorry, I'm still not seeing the point. The name hidden_stream_object is not in scope here but ourmacro_f is instead? So what?
Or, a plain function to return the stream object?
ostream& get_stream() { return hidden_stream_object; }
#define OURMACRO(EXPRESSION) get_stream()<< EXPRESSION
Okay, so I've oversimplified the example code. The point is that the boost::lambda::_1 placeholder defers the evaluation, giving you extra control over the operation. Put differently, the expression is evaluated in the context of your function rather than in the calling context. Consider: template<typename FUNCTOR> void ourmacro_f(const FUNCTOR& f) { if (some_condition) { f(hidden_ostream_object); } } or how about: template<typename FUNCTOR> void ourmacro_f(const char* expr_string, const FUNCTOR& f) { try { f(hidden_ostream_object); } catch (const std::exception& e) { hidden_ostream_object << "Exception " << typeid(e).name() << " evaluating (" << expr_string << "): " << e.what() << std::endl; } } #define OURMACRO(EXPRESSION) (ourmacro_f(#EXPRESSION, boost::lambda::_1 << EXPRESSION))
participants (6)
-
Dave Abrahams
-
Jeremiah Willcock
-
John M. Dlugosz
-
Kim Barrett
-
Michael Schulze
-
Nat Linden