我想将运行时值int v
转换为对带有非类型模板参数v
,例如template <int v> void hello()
的相应函数的调用。
这是编写它的蛮力方式:
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
}
我可以将其用于3个值,但是对于更多的值,或者当限制本身是由其他编译时值计算得出的,这是不切实际的。
如何在编译时初始化LUT 2 而不在初始化程序中明确列出各种实例hello<0>, hello<1>, ...
?
这是我想出的:
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>();
在C ++ 17中,必须有一些更简单,更好和更惯用的东西,尤其是不需要递归的东西。
2 或者,如果这是一个XY问题,如何在没有LUT(但至少具有LUT效率)的情况下实现hello_dispatch
。
答案 0 :(得分:3)
您可以直接初始化std::array
,即不需要递归地分配元素。
template<std::size_t... I>
constexpr auto make_helper(std::index_sequence<I...>) {
return std::array<fn_type *, sizeof...(I)> { hello<I>... };
}
template <std::size_t MAX>
constexpr auto make_lut() {
return make_helper(std::make_index_sequence<MAX>{});
}
答案 1 :(得分:2)
使用std::integer_sequence
和fold expressions:
GET http://127.0.0.1:8080/api/projects?filter[tasks.id]=1
{
"data" : [ ]
}
template <int... Is>
constexpr std::array<fn_type*, sizeof...(Is)> make_lut(std::integer_sequence<int, Is...>) {
std::array<fn_type*, sizeof...(Is)> res{};
((res[Is] = &hello<Is>), ...);
return res;
}
template <int Max>
constexpr auto make_lut() {
return make_lut(std::make_integer_sequence<int, Max>{});
}
static constexpr auto lut2 = make_lut<3>();
创建一个std::make_integer_sequence<int, N>{}
类型的对象。 std::integer_sequence<int, 0, 1, 2, ..., N - 1>
将每个hello<N>
分配给res[N]
。 res[Is] = &hello<Is>
折痕左侧的值应用逗号运算符。答案 2 :(得分:0)
现在,对于完全不同的东西...
如果可以使用C ++ 20,则可以使用template-lambdas,并且可以完全避免使用lut
数组
#include <iostream>
#include <utility>
template <int v>
void hello()
{ std::cout << "hello: " << v << std::endl; }
void hello_dispatch (int v)
{
[&]<int ... Is>(std::integer_sequence<int, Is...> const &)
{ ((v == Is ? (hello<Is>(), 0) : 0), ...); }
(std::make_integer_sequence<int, 100u>{}); // 100 is top limit (former lut size)
}
int main ()
{
hello_dispatch(42);
}
如果您只能使用C ++ 17 ...不是那么优雅,但是您可以使用递归通用lambda
#include <iostream>
#include <utility>
template <int v>
void hello()
{ std::cout << "hello: " << v << std::endl; }
template <int I>
using IC = std::integral_constant<int, I>;
void hello_dispatch (int v)
{
auto lf = [&](auto self, auto ic)
{ if constexpr ( ic < 100 )
v == ic ? (hello<ic>(), 0)
: (self(self, IC<ic+1>{}), 0); };
lf(lf, IC<0>{});
}
int main ()
{
hello_dispatch(42);
}