I'm watching CppCon 2015: Scott Schurr “constexpr: Applications", on 19'28" he's showing a trick to force compile time error only:
A Way to Force Compile-Time Only?
- Not within the standard
- But a hack that sometimes works
Unresolved Symbol In Throw
extern const char* compile11_bin_invoked_at_runtime;
template <typename T = std::uint32_t>
constexpr T compile11_bin(
std::size_t i = 0, // index
std::size_t b = 0, // bit count
T x = 0) // accumulator
i >= t.size() ? x : // end recursion
b >= std::numeric_limits<T>::digits ?
throw std::overflow_error("Too many bits!") :
t[i] == ',' ? compile11_bin<T>(t, i+1, b, x) :
t[i] == '0' ? compile11_bin<T>(t, i+1, b+1, (x*2)+0) :
t[i] == '1' ? compile11_bin<T>(t, i+1, b+1, (x*2)+1) :
throw std::domain_error( // Only '0', '1', and ','
Compile time errors are always better than runtime errors.
Why? Because compile time errors can be fixed without running the application, and can thus be easily fixed. By throwing an unresolved external symbol, you can force the result of
compile11_bin to be stored in a constexpr variable, which enables you to detect errors more quickly.
The example from the slide is:
constexpr auto maskA = constexpr11_bin<std::uint8_t>("1110 0000"); auto maskB = constexpr11_bin<std::uint8_t>("0001 1111");
maskA results in a compile time error, which can be easily fixed.
maskB on the other hand results in a runtime error, as
maskB is not constexpr, and so the result doesn't have to be evaluated at compile-time, and you'll get a runtime error.
compile11_bin_invoked_at_runtime is a unresolved external symbol, and every symbol has to have a definition, and so you get an error at compile-time, even if it's not the compiler per se that complains.