C++ 在constexpr函数中实例化多个模板
我正在开发一个游戏机模拟器。出于好奇,我想生成一个包含C++ 在constexpr函数中实例化多个模板,c++,templates,c++17,template-meta-programming,constexpr,C++,Templates,C++17,Template Meta Programming,Constexpr,我正在开发一个游戏机模拟器。出于好奇,我想生成一个包含run()函数指针以及其他一些有用字段的consteprOpcode对象数组 下面是一个大致工作原理的示例: #include <array> struct CPU { int some_state = 0; }; void f(CPU& cpu) { cpu.some_state = 42; } void g(CPU& cpu) { cpu.some_state = 12; } s
run()
函数指针以及其他一些有用字段的constepr
Opcode
对象数组
下面是一个大致工作原理的示例:
#include <array>
struct CPU
{
int some_state = 0;
};
void f(CPU& cpu)
{
cpu.some_state = 42;
}
void g(CPU& cpu)
{
cpu.some_state = 12;
}
struct Opcode
{
using Runner = void(*)(CPU&);
Runner run = [](CPU&) {};
/* more fields here */
};
constexpr auto gen_opcodes()
{
std::array<Opcode, 2> ret {};
ret[0] = { f };
ret[1] = { g };
return ret;
}
constexpr auto opcodes = gen_opcodes();
int main()
{
CPU cpu;
opcodes[1].run(cpu);
}
这失败了:
constexpr auto gen_opcodes()
{
std::array<Opcode, 100> ret {};
for (int i = 30; i < 50; ++i)
{
ret[i] = { f<i> };
}
return ret;
}
constexpr自动生成操作码()
{
std::数组ret{};
对于(int i=30;i<50;++i)
{
ret[i]={f};
}
返回ret;
}
注:这显然是为了举例,在实践中略有不同
原因是在这种情况下,i
不是一个常量表达式
如何在不手工编写的情况下生成这些函数模板?否则,是否有另一种“足够短”且具有我前面所述优点的解决方案
我有一些想法,但似乎都不够:
- 有状态的兰博达斯。但是,
在std::function
上下文中不起作用,因为它有一个非平凡的析构函数,并且捕获lambda不能强制转换到函数指针中constepr
- 函数对象。我不知道如何将它们以那种方式存储在
上下文中constexpr
i
您正在constepr
函数中使用std::array
的运算符[]
,因此您使用的是C++17
使用C++17,您可以使用std::index_sequence
/std::make_index_sequence
(从C++14开始提供)和模板折叠(从C++17开始)
因此,您可以分两步编写gen_操作码()
根据循环长度生成std::index_序列的第一步
constexpr auto gen_opcodes_1()
{ return gen_opcodes_2(std::make_index_sequence<20U>{}); }
constexpr自动生成操作码1()
{返回gen_操作码_2(std::make_index_sequence{})}
第二步,使用模板折叠来模拟for循环
template <std::size_t ... Is>
constexpr auto gen_opcodes_2 (std::index_sequence<Is...> const &)
{
std::array<Opcode, 100> ret {};
( (ret[30+Is] = { f<30+Is> }), ... );
return ret;
}
模板
constexpr自动生成操作码(std::index\u sequence const&)
{
std::数组ret{};
((ret[30+Is]={f}),…);
返回ret;
}
下面是一个完整的编译示例
#include <array>
struct CPU
{ int some_state = 0; };
template <int I>
void f (CPU & cpu)
{ cpu.some_state = I; }
struct Opcode
{
using Runner = void(*)(CPU&);
Runner run = [](CPU&) {};
};
template <std::size_t ... Is>
constexpr auto gen_opcodes_2 (std::index_sequence<Is...> const &)
{
std::array<Opcode, 100> ret {};
( (ret[30+Is] = { f<30+Is> }), ... );
return ret;
}
constexpr auto gen_opcodes_1()
{ return gen_opcodes_2(std::make_index_sequence<20U>{}); }
constexpr auto opcodes = gen_opcodes_1();
int main()
{
CPU cpu;
opcodes[1].run(cpu);
}
#包括
结构CPU
{int some_state=0;};
模板
无效f(CPU和CPU)
{cpu.some_state=I;}
结构操作码
{
使用Runner=void(*)(CPU&);
运行程序运行=[](CPU&){};
};
模板
constexpr自动生成操作码(std::index\u sequence const&)
{
std::数组ret{};
((ret[30+Is]={f}),…);
返回ret;
}
constexpr自动生成操作码1()
{返回gen_操作码_2(std::make_index_sequence{})}
constexpr自动操作码=gen_操作码_1();
int main()
{
中央处理器;
操作码[1]。运行(cpu);
}
#include <array>
struct CPU
{ int some_state = 0; };
template <int I>
void f (CPU & cpu)
{ cpu.some_state = I; }
struct Opcode
{
using Runner = void(*)(CPU&);
Runner run = [](CPU&) {};
};
template <std::size_t ... Is>
constexpr auto gen_opcodes_2 (std::index_sequence<Is...> const &)
{
std::array<Opcode, 100> ret {};
( (ret[30+Is] = { f<30+Is> }), ... );
return ret;
}
constexpr auto gen_opcodes_1()
{ return gen_opcodes_2(std::make_index_sequence<20U>{}); }
constexpr auto opcodes = gen_opcodes_1();
int main()
{
CPU cpu;
opcodes[1].run(cpu);
}