Library for compile time checks, header-only, requires at least C++14.
This C++ library was conceived by the need of having a compile-time assert function (not static_assert).
If you need something like
constexpr int foo(int i) {
chk::cassert(i > 2);
return i - 2;
}
then this library is for you.
Notice that in the given example it is not possible to use assert or static_assert, as the former is not constexpr, and the latter requires a constexpr-expression.
chk::cassert work like a constexpr function and can take an optional string in two forms:
-
takes a string-like (
\0terminatedconst char*,std::string) object as optional parameter:chk::cassert(i > 2, "fail"); -
the string can be computed lazily only in case of failure:
chk::cassert(i > 2, [](){/* compute string at runtime*/});
The second form is useful in order not to waste time creating an error message if the test does not fail.
Also the expression to verify can be computed lazily through a function: chk::cassert([&i](){return i > 2});
This is useful is the verification is expensive, and because chk::cassert is not a macro.
If NDEBUG is not defined, then chk::cassert compiles to a no-op, but the expression is still computed at the caller site.
If it is expensive, this is undesirable, and maybe it won’t get optimized away, especially if it has side effects like memory allocations.
By using a lambda or normal function, the compiler is able to remove the entire verification as the lambda/function is never called.
Since chk::cassert is a normal (templated) function, it can be also used in those places where assert, since it is a macro, is unsuitable, for example as parameter for an algorithm:
std::for_each(begin, end, chk::cassert)
If the expression evaluates to false at compile-time, compilation stops, while at runtime it calls abort just like assert.
assert is a debugging tool controlled by NDEBUG, which can be used to control chk::cassert too.
But if the check takes place at compile-time, it will still get executed (the motivation behind this decision is that compile-time checks take 0 time at runtime)
Nevertheless there might be situations where it makes sense (reduce compilation times) also the checks at compile-time.
This is controlled by the macro CNDEBUG.
GCC (and clang) have a very useful function when
-
one wants to take advantage of diagnostics for unreachable code
-
trying to remove useless boilerplate
-
document better some invariant through code
The function is __builtin_unreachable.
But like assert, it’s not constexpr.
There are other utilities, like chk::unreachable
chk::unreachable
-
adds the
constexprmodifier, in order to use it insideconstexprfunctions. -
has an optional message parameter, to help the developer in case
NDEBUGis not defined (similarly toassert) if the code is reached.
constexpr void foo(int i) {
if(i > 5){
//
} else if(i < 3){
//
} else {
chk::unreachable("foo should never reach this point"); //message is optional
}
}
Since it is header-only, there are multiple ways of consuming this library.
Option 1)
Just copy the include folder in you project somewhere, possibly no adjustment to the build system required
Option 2)
This is a CMake-Project, thus "build" and install the library:
cmake -S <dir of this project> -B <build directory> -DCMAKE_INSTALL_PREFIX:PATH=<optional, where to install the headers and cmake target> cmake --build <build directory> --target install
And in your CMakeLists.txt add find_package(chk REQUIRED) for importing chk as target, and adapt CMAKE_PREFIX_PATH, for example:
cmake -S <dir of your project> -B <build directory of your project> -DCMAKE_PREFIX_PATH=<installation directory of chk>
Option 3)
Use conan, the project provides a conanfile
conan create <dir of this project> <name of package>
And add to the conanfile of you project
[requires] chk/1.0@<choosen name>
For example usages, just look in the test directory.