キーをconstexpr
にしてstd :: mapを初期化したい。コードが生成されたバイナリは、キータイプの文字列が含まれています最近どの打ち鳴らすとgcc、コンパイルしている間std :: mapの初期化にC++ 11のconstexprを使用する
#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; }
:次のC++ 11 MWEを考えてみましょう
をしている理由バイナリに含まれているキーはconstexprとして使用されていますか?この現象を回避する方法はありますか?
もちろん、マップの初期化は実行時に行われます。しかし、コンパイル時にバイナリの値をconstexprに置き換えてはいけませんか?
注:これはもちろん簡単な例です。私は異なったブーストの構造があることを知っています。このユースケースにはより適しています。私は特にに興味があり、なぜこれが起こっているのですか?
[編集]
この現象は、最適化が有効かどうかに関係なく発生します。 次のコードは、バーは、文字列テーブル内の唯一のユーザー定義の文字列であることをコンパイルします。
#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;
}
}
}
私は
$ 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
constexprは、コンパイラがコンパイル時に結果を使用できることを意味します。しかし、それはすべての評価がコンパイル時に行われなければならないという意味ではありません。 C++には、コンパイル時の評価が非常に難しい可能性がありません。コンパイラの中には、「式が複雑になる」と不平を言うものがあります... – Klaus
最適化でコンパイルしましたか? [clang](https://godbolt.org/g/AzZeMg)には結果として得られるアセンブリのキーがありません。 – Rakete1111
編集 – muffel