我想初始化一个 std::map ,键是 constexpr
。考虑以下 C++11 MWE:
#include <map>
using std::map;
constexpr unsigned int str2int(const char* str, const int h = 0) {
return !str[h] ? 5381 : (str2int(str, h + 1) * 33) ^ str[h];
}
const map<unsigned int, const char*> values = {
{str2int("foo"), "bar"},
{str2int("hello"), "world"}
};
int main() { return 0; }
当代码编译最近的 clang 和 gcc 时,生成的二进制文件将包含键类型的字符串:
为什么密钥包含在二进制文件中,即使它们被用作 constexpr 的?有什么办法可以解决这种行为?
当然,地图初始化将在运行时发生。但是不应该在编译时用 constexpr 替换二进制文件中的值吗?
注意:这当然是一个简化的例子。我知道有不同的 升压 结构可能更适合这个用例。我对 为什么 会发生这种情况特别感兴趣。
[编辑]
无论是否启用优化,都会发生该行为。以下代码编译时 bar 是字符串表中唯一的用户定义字符串:
#include <map>
#include <iostream>
#include <string>
using namespace std;
constexpr unsigned int str2int(const char* str, const int h = 0) {
return !str[h] ? 5381 : (str2int(str, h + 1) * 33) ^ str[h];
}
int main() {
string input;
while(true) {
cin >> input;
switch(str2int(input.c_str())) {
case str2int("quit"):
return 0;
case str2int("foo"):
cout << "bar" << endl;
}
}
}
为了验证结果,我使用了一个小的 shell 脚本
$ for x in "gcc-mp-7" "clang"; do
$x --version|head -n 1
$x -lstdc++ -std=c++11 -Ofast constexpr.cpp -o a
$x -lstdc++ -std=c++1z -Ofast constexpr.cpp -o b
strings a|grep hello|wc -l
strings b|grep hello|wc -l
done
gcc-mp-7 (MacPorts gcc7 7.2.0_0) 7.2.0
1
0
Apple LLVM version 8.1.0 (clang-802.0.38)
1
0
原文由 muffel 发布,翻译遵循 CC BY-SA 4.0 许可协议
这个线程并不是很新鲜,但有时仍然需要坚持 c++11:|
如何使用 constexpr 函数来设置键:
一旦它们变得更大,“单一来源”密钥就可以简化此类地图的维护……
我的小测试程序
如果使用 gcc 7.5 编译,则工作正常并且不包含任何关键字符串