Note that there are some explanatory texts on larger screens.

plurals
  1. POC++11 lambdas passed as std::function params - dispatching on return type
    text
    copied!<p>The scenario:</p> <p>We have an API that has a generic error handling interface. It is a C API, so it tells us that after every API function called, we need to execute some boilerplate like this:</p> <pre><code>if (APIerrorHappened()) { APIHandle h; while(h = APIgetNextErrorContext(...)) { cerr &lt;&lt; APIgetText(h) &lt;&lt; endl; } } </code></pre> <p>You obviously hate repeating yourself, so you want to encapsulate this handling in a macro that allows you to write code like this:</p> <pre><code>... // this API call returns something APItype foo = MYMACRO(APIsomeFunction1(...)); // this one doesn't MYMACRO(APIsomeFunction2(...)); // neither does this (glCompileShader) MYMACRO(APIsomeFunction3(...)); ... </code></pre> <p>You can also think of this in terms of aspect-oriented programming - imagine that the macro adds logging, sends info to remote monitor, whatever... The point is that it is supposed to encapsulate an expression, do whatever <strong>around</strong> it, and return whatever type the expression returns - and of course the expression may not return <em>anything</em>.</p> <p>Which means you can't just do </p> <pre><code>#define MYMACRO(x) { auto x = expr(); ... } </code></pre> <p>...because in some cases, the expression doesn't return anything!</p> <p>So... How would you do that?</p> <p>Please don't suggest encapsulating the complete statement inside the macro...</p> <pre><code>#define MYMACRO(x) \ { \ /* ... stuff ... */ \ x; \ // ... stuff } </code></pre> <p>...since this would never work for stuff like:</p> <pre><code>if (foo() || APIfunctionReturningBool(...) || bar()) { ... APIfunction1(); ... } else if (APIOtherfunctionReturningBool() || baz()) { ... APIfunction2(); ... } </code></pre> <p>...you engulf all the if statement? Its actions include other API calls, so... macro within macro? Debugging just became hell.</p> <p>My own attempt is below, using lambdas and std::function - but it is arguably, ugly... I could not pass a lambda of the expression directly to a template that takes std::function (to specialize based on the lambda's return type), so the code turned out rather nasty.</p> <p>Can you think of a better way?</p> <pre><code>void commonCode(const char *file, size_t lineno) { // ... error handling boilerplate // ... that reports file and lineno of error } template &lt;class T&gt; auto MyAPIError(std::function&lt;T()&gt;&amp;&amp; t, const char *file, size_t lineno) -&gt; decltype(t()) { auto ret = t(); commonCode(file,lineno); return ret; } template&lt;&gt; void MyAPIError(std::function&lt;void(void)&gt;&amp;&amp; t, const char *file, size_t lineno) { t(); commonCode(file,lineno); } template &lt;class T&gt; auto helper (T&amp;&amp; t) -&gt; std::function&lt;decltype(t())()&gt; { std::function&lt;decltype(t())()&gt; tmp = t; return tmp; } #define APIERROR( expr ) \ return MyAPIError( helper( [&amp;]() { return expr; } ), __FILE__, __LINE__); </code></pre> <p><strong>UPDATE, an addendum to KennyTM's excellent solution</strong></p> <p>I placed the actual OpenGL code that triggered this question <a href="http://pastebin.com/fA4qZaaB" rel="nofollow">here</a>. As you can see, the error checking code did more than just print - it also threw an exception that the user code could then handle. I am adding this addendum to note that with KennyTM's solution, you end up throwing this exception from a destructor, and that this is OK (read on):</p> <pre><code>struct ErrorChecker { const char *file; size_t lineno; ~ErrorChecker() { GLenum err = glGetError(); if (err != GL_NO_ERROR) { while (err != GL_NO_ERROR) { std::cerr &lt;&lt; "glError: " &lt;&lt; (char *)gluErrorString(err) &lt;&lt; " (" &lt;&lt; file &lt;&lt; ":" &lt;&lt; lineno &lt;&lt; ")" &lt;&lt; std::endl; err = glGetError(); } throw "Failure in GLSL..."; } } }; </code></pre> <p>The reason it is OK to throw from this destructor, is explained in the <a href="http://www.parashift.com/c++-faq-lite/exceptions.html#faq-17.9" rel="nofollow">C++ FAQ</a>:</p> <blockquote> <p>The C++ rule is that you must never throw an exception from a destructor that is being called during the "stack unwinding" process of another exception... you can say never throw an exception from a destructor <strong>while processing another exception</strong>. </p> </blockquote> <p>In our case, we want the user code (that calls the special macro) to handle the exception; so we need to know for certain that our "throw" in the ErrorChecker's destructor is the first one - i.e. that the actual C API called can never throw. This is easily accomplished with this form:</p> <pre><code>#define GLERROR(...) \ ([&amp;]() -&gt; decltype(__VA_ARGS__) \ { \ ErrorChecker _api_checker {__FILE__, __LINE__}; \ (void) _api_checker; \ try { \ return __VA_ARGS__; \ } catch(...) {} \ } ()) </code></pre> <p>This form of the macro guarantees that the actual C API (called via <strong>VA_ARGS</strong>) will never throw - and therefore, the "throw" in ErrorChecker's destructor will always be the <strong>first one</strong> doing it. </p> <p>So this solution covers all angles of my original question - many thanks to <a href="http://nerds-central.blogspot.com/2012/03/c11-generic-error-catcher.html" rel="nofollow">Alexander Turner</a> for providing it.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload