I want to initialize a std::map with the keys being a constexpr
. Consider the following 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; }
While the code compiles which recent clang and gcc, the resulting binary will contain the strings of the key type:
Why are the keys contained in the binary even though they are used as constexpr's? Any way to work around this behavior?
Of course the map initialization will occur at runtime. But shouldn't the values in the binary be replaced with the constexpr's at compiletime?
Note: This is of course a simplified example. I know there are different boost structures which may be more suitable for this use case. I'm especially interested in why this is happening.
[Edit]
The behavior occurs no matter if optimizations are enabled or not. The following code compiles with bar being the only user defined string in the string table:
#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;
}
}
}
To verify the results I was using a small shell script
$ 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