
On Thu, Jan 22, 2015 at 3:49 PM, Edward Diener <eldiener@tropicsoft.com> wrote:
On 1/22/2015 6:05 PM, Matt Calabrese wrote:
On Wed, Jan 21, 2015 at 4:52 PM, Matt Calabrese <rivorus@gmail.com> wrote:
I've found it useful, especially in tests, to easily be able to do
expression validity checking via SFINAE in a static assert.
Bump, and also a couple of additional macros for checking constexpr-ness of an expression are linked farther down in this email, using similar tricks as the SFINAE checks int the previous email (pushing more complicated checks into the body of a lambda such that the macro expands to an expression).
Motivation for this is that often when writing templated code it is difficult to be certain that a specific instantiation is actually constexpr even if the constexpr keyword is used with the function template. For instance, for a matrix type whose value type is a template parameter T, it can be difficult to know if matrix<T>'s multiplication operation actually results in a constexpr object, even if it has constexpr inputs. Particularly when designing such a library, it is useful to be able to write simple tests that check the constexpr-ness of a specified expression in the form of a static_assert. A proof-of-concept implementation of this is linked below:
As an example of such a usage:
////////////////////
int foo(int) { return 0; }
STATIC_ASSERT_CONSTEXPR ( (constexpr int) var = 5, foo(var) );
////////////////////
Produces the error:
prog.cpp:70:1: error: static assertion failed:
********************
Given: constexpr int var = 5;
The following expression was expected to be constexpr but was not: foo(var)
********************
This looks interesting but I am confused about where this implementation is. Is it available somewhere ? is it documented at all ? Are there examples/tests ? Is there a good general of when some of these macros should/would be used in template code ?
Slimmed-down implementations were linked in the emails (this is just a request for comments, I'm not proposing anything -- more just seeing if people find this useful so that I can consider proposing a more capable boosty implementation): SFINAE checks: http://ideone.com/RHd6FM constexpr checks: http://ideone.com/ko09KQ The examples are self-contained and able to be compiled/run in the browser if you want to play around with them. Both examples have example uses at the bottom of the file. I apologize that they are not documented -- consider them just as a proof of concept to show that the macros work. Describing how they work is a bit complicated and I didn't feel like going into details. If any of the magic needs clarification, let me know. For details on how to invoke the macros linked, the basic pattern for the SFINAE checks are: STATIC_ASSERT_VALID ( (int) a, // This says "given a variable a of type int..." ++a // Would the expression ++a be "valid" ); The "invalid" expression check works similarly. Underneath the hood is an IS_VALID_EXPR macro that has the same form and is usable on its own, yielding a constexpr bool expression. For instance, you can use it to easily do: template <class T> struct has_preincrement_operator : std::integral_constant<bool, IS_VALID_EXPR((T) object, ++a)> {}; The above checks that T supports ++a, without the user having to do SFINAE directly (it also does not place any other requirements on T, other than it not being a void type or an incomplete reference type, and probably a couple of other oddball cases, but those can all be handled gracefully with a slightly more complicated implementation). The constexpr macros work in the same manner, only you need to initialize your "given" objects. Another limitation of the constexpr facility is that your givens must all be constexpr if you reference them in the expression that you are checking. It also will produce a compile-time error instead of a nice static_assert if the expression yields void (there might be some magic to fix, but I haven't given it much thought). It will also fail if your expression is simply the name of a global object (there also might be a way around this). It looks like you are saying that in place of BOOST_STATIC_ASSERT one can
use your macros at compile time to produce compile time errors, but the majority of C++ expressions have to be evaluated at run-time. So is this strictly for compile-time expressions or what ?
These are strictly compile-time checks. I find them particularly useful for concept checking and for writing unit tests.
Your original OP looked like it worked with run-time expressions ( ++a, a+b etc. ).
It is doing expression-validity checking (using C++11 extended SFINAE rules). The ++a in the example email is checking if ++a would be valid if "a" were of the specified type during substitution. A more boostified version which I have implemented locally allows the SFINAE checks to work with any number of "given" declarations and any number of expressions. It only depends on Boost.Preprocessor. -- -Matt Calabrese