Reputation: 6405
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( constexpr_txt t, std::size_t i = 0, // index std::size_t b = 0, // bit count T x = 0) // accumulator { return 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 ',' compile11_bin_invoked_at_runtime); }
I'm curious here, what's the motivation to force a constexpr to have compile time error only?
Upvotes: 3
Views: 328
Reputation: 48918
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");
Here, 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.
That's because compile11_bin_invoked_at_runtime
is an 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.
Upvotes: 3