I have a class C in the namespace N with a public template member function F as follows:
namespace N {
class C {
public:
template<int I>
void F() {
// ...
}
};
};
The values of I for N::C::F<I> are not known until runtime. However, the value of I is constrained such that 0 <= I < 2^8. I am looking for a way to force this function to expand the template to all 256 possible forms.
So far, I have manually created a static array within a second function of C that points to every possible function:
template<int I>
void F() {
// ...
}
void G(int I) {
static void(* const funcs[256])() = {
F<0>, F<1>, F<2>, ...
};
funcs[I]();
}
though I am left wondering if there is a better way. I already have a macro in N that is responsible for constructing a separate struct for each value of I (for use by F itself) and was looking if I could possibly integrate the instantiation of the template member function somehow in it:
template<int> struct S;
#define M(I, n) \
template<> struct S<I> { \
static const char name[] = #n; \
/*
Some how instantiate the function here, like (just guessing here):
static const SEvaluator<I> eval = &C::F<I>;
given
template<int I>
using SEvaluator = void(*)();
*/
};
M(0, "foo"); M(1, "bar");
#undef M
My proposed method does not work as is and the compiler complains about F not being a constexpr. F manipulates several variables of C and calls external methods and could not be declared constexpr. Is there a way to salvage this or do I have to resort to my first hackish method?
You can use an index_sequence<I...> (C++14) and expand I into the static array.
template<std::size_t... Is>
void G(int i, std::index_sequence<Is...>) {
using C = void(C::*)();
static C funcs[sizeof...(Is)] = { &C::F<Is>... };
(this->*funcs[i])();
}
void G(int i) {
G(i, std::make_index_sequence<256>());
}
For a non-C++14 solution you can write your own version of an index_sequence:
template<int... Is>
struct index_sequence { };
template<int N, int... Is>
struct make_index_sequence : make_index_sequence<N - 1, N - 1, Is...> { };
template<int... Is>
struct make_index_sequence<0, Is...> : index_sequence<Is...> { };
Apparently I've been bested by Batman. I'll post this anyway : the principle is the same, it's just done another way around.
template <std::size_t... Idx>
auto const &makeFunctions(std::index_sequence<Idx...>) {
static auto funcs = {&N::C::F<Idx>...};
return funcs;
}
auto const &function(std::size_t i) { return *(begin(makeFunctions(std::make_index_sequence<256>{})) + i); }
Call :
N::C c;
for(int i = 0; i < 10; ++i)
(c.*function(i))();
Live on Coliru
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With