Boost logo

Boost :

Subject: [boost] RFC Expression Validity Asserts
From: Matt Calabrese (rivorus_at_[hidden])
Date: 2015-01-21 19:52:51


I've found it useful, especially in tests, to easily be able to do
expression validity checking via SFINAE in a static assert. In other words,
it's frequently useful to want to quickly test to make sure that a
particular expression does or does not compile, similar in some ways to a
concepts-lite usage pattern. The general idea is that you want to static
assert that, given a series of object declarations of a specific type, a
specified expression or series of expressions that deal with those objects
would or would not cause substitution to fail had the object types been
dependent on a template parameter.

It internally relies on a macro that is invoked as such:

//////////
IS_VALID_EXPR(
    (int) a,
    (float) b,
    // etc..

    (a + b)
    (a - b)
    // etc.
)
//////////

The above macro invocation results in an expression that is a constexpr
bool which is true iff substitution would not fail.

With the above macro, one can do, for instance:
static_assert(IS_VALID_EXPR((const int) a, ++a), "Some error message.");

I've found this pattern so common that I've created a macro that takes such
a series of declarations and expressions and automatically produces a
simple static_assert, outputting the declarations and the expression that
did not compile.

A slimmed down version of this macro can be toyed with via the link below
(this slim version allows only one declaration and one expression per
macro):

http://ideone.com/RHd6FM

Briefly, using the macro as such:

STATIC_ASSERT_VALID
(
    (const int) a,
    ++a
);

is able to produce a very human-readable error message:

prog.cpp:58:1: error: static assertion failed:

********************

Given:
    const int a;

The following expression was expected to compile but did not:
    ++a

********************

There is a similar macro for verifying that an expression does not compile,
which I find is much more useful in practice. Notable is that the validity
macro is an expression -- no statement or other declarations are introduced
-- and the static assert macro produces a single static_assert. This means
that you can use the assertion macro in the normal scopes that any
static_assert can be used (namespace scope, class scope, function
scope...). One limitation is that because it uses lambdas behind the
scenes, the context in which the validity macro may be used is slightly
restricted (I.E. it can't be used in an un-evaluated context).

Is this something people would generally find useful? If it is considered
generally useful, I don't think it's really worthy of its own library, so
where would it go? Years ago I probably would have just assumed utility,
but I'm not really sure where it would go in the modern boost structure.
The slim version can easily have no dependencies, though the more general
solution ideally depends on Boost.Preprocessor.

The macros themselves require C++14, though slightly less-useful forms
(ones that introduce additional declarations) could be made that would work
in C++11.

-- 
-Matt Calabrese

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk