I was unaware of the consteval feature, that would be really useful for some of the things I’ve done in the past (working on performance sensitive code and JITs there times where it would be nice to not have to worry about the optimizer spontaneously not doing things at compile time).
Using consteval certainly makes this simpler, but you can force constant evaluation in C++11 and with C++14 / C++17 features you can clean it up a bit. The key point is that template arguments must be evaluated at compile time and so if you pass a constexpr value through a template parameter then it will either be evaluated at compile time or fail to compile. You can then wrap this behaviour like this (this is C++17, which has been the default for everything that I’ve worked on for so long that I can’t remember which bits don’t work with C++14 / C++11, but you can do the same thing with slightly more clunky syntax in C++11):
using type = std::decay_t<decltype(Val)>;
static constexpr type value = Val;
inline constexpr auto force_const_v = force_const<Val>::value;
int definitely_works = force_const_v<12>;
constexpr auto fn()
auto works_if_fn_evaluates_at_compile_time = force_const_v<fn()>;
If fn fails to evaluate at compile time then you’ll get a compile error.
Ah good point, although I think back when we were doing these terrible things we didn’t have support for constexpr either :D
Or maybe we did and I didn’t think about it. Hmm. As I write this I’m not 100% sure.
That said these days I work on the compiler, so that level of perf optimization isn’t something I have to suffer through anymore :D