I'd like to convert a runtime value int v into a call to a corresponding function with non-type template parameter v, e.g., template <int v> void hello().
Here's the brute force way of writing it:
using fn_type = void();
template <int v>
void hello() {
// of course ITRW this function requires v to be a
// constexpr value
printf("hello: %d\n", v);
}
static std::array<fn_type *, 3> lut = {
hello<0>,
hello<1>,
hello<2>
};
void hello_dispatch(int v) {
lut[v](); // we don't handle OOB values b/c we are naughty like that
}
I can live with that for 3 values, but this gets impractical with more values, or when the the limit is itself calculated from some other compile-time value.
How can initialize the LUT2 at compile-time without explicitly listing the various instantiations hello<0>, hello<1>, ... in the initializer?
This is what I came up with:
template <size_t I, size_t MAX>
constexpr void make_helper(std::array<fn_type *, MAX>& a) {
if constexpr (I < MAX) {
a[I] = hello<I>;
make_helper<I + 1, MAX>(a);
}
}
template <size_t MAX>
constexpr std::array<fn_type *, MAX> make_lut() {
std::array<fn_type *, MAX> ret{};
make_helper<0, MAX>(ret);
return ret;
}
static constexpr std::array<fn_type *, 3> lut2 = make_lut<3>();
There has got to be something simpler, better and more idiomatic in C++17 - in particular, without needing recursion.
2 Or, in case this an an XY problem, how can I implement hello_dispatch without a LUT (but with at least the efficiency of the LUT).
hello, it might even be faster to pass the argument at runtime rather than use a lookup table.helloreally just contained a printf, there would be no point. In reality,hellohas an implementation which requiresvto be a compile-time known value.