【发布时间】:2015-04-24 21:23:36
【问题描述】:
基本上我希望我的代码能够做到这一点:
Engine.getById(WSID('some-id'));
哪个应该被改造
Engine.getById('1a61bc96');
就在被编译成 asm 之前。所以在编译时。
这是我的尝试
constexpr int WSID(const char* str) {
boost::crc_32_type result;
result.process_bytes(str,sizeof(str));
return result.checksum();
}
但我在尝试使用 MSVC 18(CTP 2013 年 11 月)编译时得到了这个
error C3249: illegal statement or sub-expression for 'constexpr' function
我怎样才能得到WSID函数,使用这种方式或任何方式,只要它是在编译期间完成的?
试过这个:Compile time string hashing
warning C4592: 'crc32': 'constexpr' call evaluation failed; function will be called at run-time
编辑:
我在 Jason Gregory 的 Game Engine Architecture 中第一次听说这种技术。我联系了作者,他很乐意回答我这个问题:
我们所做的是将我们的源代码通过一个自定义的小型预处理器,该预处理器搜索
SID('xxxxxx')形式的文本,并将单引号之间的任何内容转换为十六进制文本 (0xNNNNNNNN) . [...]您也可以通过宏和/或一些模板元编程来完成它,尽管正如您所说,让编译器为您完成这种工作很棘手。这并非不可能,但编写自定义工具更容易、更灵活。 [...]
还请注意,我们为
SID('xxxx')文字选择了单引号。这样做是为了让我们在代码编辑器中获得一些合理的语法高亮显示,但是如果出现问题并且一些未经预处理的代码通过编译器,它会抛出语法错误,因为单引号通常保留用于单字符文字。还请注意,让您的小型预处理工具将字符串缓存在某种数据库中是至关重要的,这样可以在给定哈希码的情况下查找原始字符串。当您调试代码并检查
StringId变量时,调试器通常会向您显示相当难以理解的哈希码。但是使用 SID 数据库,您可以编写一个插件,将这些哈希码转换回它们的字符串等价物。这样,您将在监视窗口中看到 SID('foo'),而不是0x75AE3080[...]。此外,游戏应该能够加载相同的数据库,以便它可以在屏幕上打印字符串而不是十六进制哈希码以进行调试[...]。
虽然预处理有一些主要优点,但这意味着我必须准备某种修改文件的输出系统(那些将存储在其他地方,然后我们需要告诉 MSVC)。所以它可能会使编译任务复杂化。有没有办法用 python 预处理文件而不用头疼?但这不是问题,我仍然对使用编译时函数感兴趣(关于缓存我可以使用 ID 索引)
【问题讨论】:
-
@Nim 所以我要改成一行?
-
@Vinz243 如果您使用的是 C++11 而不是 -14,可以。除非您仍然可以说服编译器在编译时运行非 constexpr 函数。
-
几年前有一个代码高尔夫可以做到这一点。 codegolf.stackexchange.com/questions/3268/…
-
第一条错误消息“type not allowed for 'constexpr'”是错误的或具有误导性:
std::string const&是文字类型(因为它是引用),因此允许作为函数参数的类型一个 constexpr 函数。 clang++ 和 g++ 也接受它(在 C++11 模式下)。
标签: c++ c++11 visual-studio-2012 constexpr compile-time