我想用键为constexpr
初始化一个std::map。考虑以下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时,生成的二进制将包含键类型的字符串:
为什么这些键包含在二进制文件中,即使它们被用作警察的呢?有办法解决这个问题吗?
当然,映射初始化将在运行时进行。但是,二进制文件中的值不应该在编译时被参数替换吗?
注:这当然是一个简化的例子。我知道有不同的boost结构可能更适合这个用例。我特别感兴趣的是,为什么会发生这种情况。
编辑
无论是否启用优化,都会发生这种行为。下面的代码编译时,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
发布于 2018-12-20 00:27:41
仅仅声明为const是不够的。这些字符串包含在二进制文件中,因为:
const map<unsigned int, const char*> values
是康斯特,但不是警察。当程序启动时,它将运行“str2int”,而不是在编译时运行。const只会保证它不会允许进一步的修改,但不会使编译时间受到影响。
它的接缝,你正在寻找的Serge的冷冻集装箱- https://github.com/serge-sans-paille/frozen
虽然我不知道它是否能在C++11上工作,但是如果你想提高性能,那肯定值得一试。
您可以创建在编译时进行散列的映射,并将为您提供产生完美哈希函数的额外好处--允许在O(1)时间(恒定时间)访问所有键。
它确实是gperf非常有能力的替代品。
目前,Clang和GCC对您在编译时能够处理的键的数量施加了限制。在我的1G RAM VPS上生成一个带有2048个键的地图是可以的,只有clang才行。GCC现在更糟了,他会更快地吃掉你所有的内存。
发布于 2017-11-12 11:22:34
我不能用g++ (主干)或clang++ (主干)进行复制。我使用了以下标志:-std=c++1z -Ofast
。然后,我用strings
检查了编译后的二进制文件的内容:"foo"
和"hello"
都没有。
是否已启用优化进行编译?
无论如何,使用str2int
并不强制进行编译时评估。为了强迫它,你可以:
constexpr auto k0 = str2int("foo");
constexpr auto k1 = str2int("hello");
const map<unsigned int, const char*> values = {
{k0, "bar"},
{k1, "world"}
};
发布于 2017-11-12 11:39:32
https://stackoverflow.com/questions/47248107
复制相似问题