在constexpr函数中插入许多模板
Instanciating many templates in constexpr function
我正在开发GameBoy模拟器。出于好奇,我想生成一个constexpr
Opcode
对象的数组,其中包含run()
函数指针和其他一些有用的字段。
下面是一个大致工作方式的示例:
#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
的原因是我希望编译器对其进行良好的优化。根据我的理解,如果数组只有const
,编译器将更难优化掉run()
调用,因为这些调用是以编译器应该内联的方式单独调用的,即if (something == 0x00) { opcodes[0x00].run(blahblah); }
。
然而,这种方法的兴趣是同时生成一堆opcodes
。我想到了使用模板函数,当一些opcodes
进入一个模式时,我应该很容易一次生成几十个opcodes
!
但是,尽管以下方法有效:
template<int i>
void f(CPU& cpu)
{
cpu.some_state = i;
}
/* ... */
constexpr auto gen_opcodes()
{
std::array<Opcode, 2> ret {};
ret[0] = { f<3> };
ret[1] = { f<2> };
return ret;
}
此操作失败:
constexpr auto gen_opcodes()
{
std::array<Opcode, 100> ret {};
for (int i = 30; i < 50; ++i)
{
ret[i] = { f<i> };
}
return ret;
}
注意:这显然是为了举例,在实践中略有不同。
原因是i
在这个上下文中不是一个常量表达式。
如果不手工编写,如何生成这些函数模板否则,是否有另一种"足够短"的解决方案,并且具有我之前谈到的优势?
我有一些想法,但似乎都不够:
- 有状态的lambdas。然而,
std::function
在constexpr
上下文中不起作用,因为它有一个非平凡的析构函数,并且捕获lambda不能转换为函数指针 - 函数对象。我不知道如何在
constexpr
上下文中以这种方式存储它们
原因是i在这个上下文中不是一个常量表达式
所以诀窍是在常量表达式中转换i
。
您在constexpr
函数中使用的是std::array
的operator[]
,所以您使用的是C++17。
使用C++17,您可以使用std::index_sequence
/std::make_index_sequence
(从C++14开始提供(和模板折叠(从C++17开始(。
因此,可以分两步编写gen_opcodes()
。
第一步,生成具有环路长度的std::index_sequence
constexpr auto gen_opcodes_1()
{ return gen_opcodes_2(std::make_index_sequence<20U>{}); }
第二步使用模板折叠来模拟for loop
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;
}
以下是的完整编译示例
#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);
}
- 使用C++库在Android项目中修改gradle中的cmake参数,用于插入指令的测试
- 有关插入适配器的错误。[错误]请求从 'back_insert_iterator<vector<>>' 类型转换为非标量类型
- 预处理器:插入结构名称中的前一个行号
- 在未初始化映射的情况下,将值插入到映射的映射中
- 如何在c++中只将键插入到bimap的一侧
- 如何将结构插入到集合中并打印集合的成员
- C++json插入数组
- Visual Studio 2019:插入多个C++风格的单行注释
- nlohmann-json将一个数组插入到另一个数组中
- 有效地使用std::unordered_map来插入或增加键的值
- 在混合代码库中将C转换为C++时出现许多包含错误
- 为字符串中每 N 个字符插入空格的函数没有按照我认为的方式工作?
- 正在插入动态数组
- 插入或删除时获取usb的dos_name
- 为什么模数运算符不适用于该代码
- 如何在C++中使用X509证书模在令牌中查找私钥
- 叮叮当当在修复时插入多个"覆盖"说明符
- 链表c++插入,所有情况都已检查,但没有任何工作
- 在constexpr函数中插入许多模板
- 如何将许多元素插入到具有相同值的 std::map