gpt4 book ai didi

c++ - 使用 c++ 11 constexpr 进行 std::map 初始化

转载 作者:塔克拉玛干 更新时间:2023-11-02 23:39:37 33 4
gpt4 key购买 nike

我想用 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 时,生成的二进制文件将包含 key 类型的字符串:

C String Literals

为什么 key 包含在二进制文件中,即使它们被用作 constexpr's?有什么方法可以解决此问题?

当然, map 初始化将在运行时发生。但是二进制文件中的值不应该在编译时用 constexpr 替换吗?

注意:这当然是一个简化的例子。我知道有不同的 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

最佳答案

这个线程不是很新鲜,但有时仍然需要坚持使用 c++11 :|

如何使用 constexpr 函数来设置键:

constexpr int makeKey(const char* s) { // c++ refused 'auto' here
return str2int(s); // using str2int from above
}

const std::map<unsigned int, const char*> values = {
{k0, "bar"}, // these require another declaration (see above)
{k1, "world"},
{makeKey("its"), "me"} // this initialization is 'single source'
};

一旦 map 变大,“单一来源”键简化了此类 map 的维护......

我的小测试程序

...

int main(int argc, char** argv) {

for(int i(1);i<argc;++i) {
const std::map<unsigned int, const char*>::const_iterator cit(values.find(str2int(argv[i])));
std::cout << argv[i] << " gets " << (cit==values.cend()?"nothing":cit->second) << std::endl;
}

return 0;
}

如果使用 gcc 7.5 使用

--std=c++11 -O0
编译,则工作正常并且不包含任何关键字符串

关于c++ - 使用 c++ 11 constexpr 进行 std::map 初始化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47248107/

33 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com