C++ std::mapでconstがどうの、と怒られる件
ものすごく初歩的な話なのだけど、久々にハマった(しかも2度目)ので忘れないよう記録。
std::mapで、コンパイル時にこういう怒られ方したことないですか?
error: passing 'const std::map
....の部分は面倒なのではしょってしまいましたが。
何をやって怒られたかというと、こんな感じのコードです。
class MyClass { double weightA_; double weightB_; void RestoreWeight(const std::map<std::string, double> &wmap) { weightA_ = wmap["A"]; weightB_ = wmap["B"]; } };
何がイカンかというと、mapのオペレータはconstがついてるmapには使えない、ということです。
ちょっと考えれば当たり前で、mapのオペレータというのは、引数で与えるキーに対応するエントリがない場合、そのキーのためのエントリを作るんだから、const functionになりようがないんですよね。
でも、個人的には、const 戻り値 operator[](キー)const みたいなのも存在してそうな気がしてしまうので、こういう失敗をする、と……。
というわけで、上の例は、このように書くしかなさそう。
class MyClass { double weightA_; double weightB_; double GetValue(const std::map<std::string, double> &wmap, const std::string &key) { std::map<std::string, double>::const_iterator i = wmap.find(key); if (i == map.end()) return 1.0; // default weight return i->second; } void RestoreWeight(const std::map<std::string, double> &wmap) { weightA_ = GetValue(wmap, "A"); weightB_ = GetValue(wmap, "B"); } };
constは正直うざいけど、上の怒られるコードが許されたら多分計算結果は怪しいことになるので、こういうときC++比較的安全だな、と思う。。
追記。
上記GetValue関数をテンプレートにして、どこでも使えるようにしようとしてハマった。
#include <map> namespace Utils { template <class X, class Y> const Y &GetMapValue(const std::map<X,Y> &m, X x) const { std::map<X,Y>::const_iterator i = m.find(x); if (i == m.end()) { log_error("Failed to extract map value."); } return i->second; } }
これをコンパイルすると、こんな感じで怒られます。
error: expected ‘;’ before ‘i’
なんで';'が必要やねん、とえらくハマったら、要するに、std::map
というわけで、その行を
typename std::map<X,Y>::const_iterator i = m.find(x);
としたら、とりあえずコンパイルは通った。これでまともに動くかは現在テスト中。