mapよりもunordered_mapを使おう
unorderedとは
要するにハッシュです。検索が早くなるので基本的にはunordered_mapを使いましょう。
mapはorderedつまり常にソートされた状態で保持されますが、これが有効に働くことは連想配列的な使い方ではまず無いでしょう。
でもkeyに複雑な値が来る場合は辛い
unordered_mapではkey値からハッシュ値が計算できないと機能しません。
その為、key値に複雑な型が来る場合はハッシュの計算仕方を教えてあげなければいけません。
#include<iostream> #include<unordered_map> #include<functional> namespace torini{ struct Key{ int value = 0; // keyは等号を処理できなければ同じか判断できません bool operator==(const Key& other) const{ return value == other.value; } }; struct Hash{ std::size_t operator()(const Key& key) const{ // ここに良い感じのハッシュ関数を書きましょう return 0; } }; using Map = std::unordered_map<Key, int, Hash>; } int main(){ torini::Map map; // map.insert(std::make_pair(torini::Key(), 1));よりもオススメ map.emplace(torini::Key(), 1); // 1が出力される std::cout << map.find(torini::Key())->second; }
妥協策
定義されてあるようなプリミティブな型はunordered_mapを使い、他はmapを使う。 mapで速度的な負担が計測されたらHashを書く。で良いんじゃないですかね!
探して見つかった場合と見つからなかった場合の処理
C++14の機能を利用しているのでコンパイラによってはビルドが通らないです。
ありがち
処理の分割がいまいちで、コードを読む時に分かりにくいです。
また、for内で読み込みと書き込みを同時に行っているのは良くない書き方の兆候です。
#include<vector> #include<utility> int main(){ std::vector<std::pair<bool, int>> v; // スコープが長いフラグ変数は怖い bool find = false; for(auto &&item: v){ if(item.first){ // ここでうっかり要素の追加とかすると危険な可能性がある item.second = 5; find = true; break; } } if(find){ // ... } else { // ... } }
標準ライブラリ
こういう処理はfind_ifを使うと良い感じに書けます。
#include<vector> #include<utility> #include<algorithm> int main(){ std::vector<std::pair<bool, int>> v; auto result = std::find_if(v.begin(), v.end(), [](const auto &item){ return item.first; }); // ちょっとここがダサい if(result != v.end()){ result->second = 5; // ... } else { // ... } }
linq的なアプローチ
何となく意図が掴めれば良いという感じで書いたコードなのでちゃんと動きません。
しっかりとしたlinq的な挙動が良いのならcpplinqを参照してください。
LINQ for C++ - Home
要するに対象を絞った後で処理をするテンプレートの様なものです。
このままだと上手く代入できません。
この辺の問題でしょうか?どちらにしろ理解不足です。
c++ - std::optional specialization for reference types - Stack Overflow
#include<vector> #include<utility> #include<experimental/optional> template<class Container, class Func> auto Where(Container &v, Func func) // optionalにはautoが効かない。ぐぬぬ -> std::experimental::optional<typename Container::value_type> { for(auto &&item: v){ if(func(item)){ return item; } } return std::experimental::nullopt; } int main(){ std::vector<std::pair<bool, int>> v; auto target = Where(v, [](auto&& item){ return item.first; }); if(target){ // ここでの代入が上手く機能しないのでもう少し考える必要がある (*target).second = 5; // ... } else { // ... } }
C++14の簡単に利用できる便利な機能
ラムダ引数の自動化
int main(){ std::vector<int> v; // ラムダの引数にautoが使える std::for_each(v.begin(), v.end(), [](auto i){ std::cout << i; }); }
ラムダ引数が複雑になった場合記述するのは冗長です。
その冗長性が省略できるのは簡単でかつ便利です。
javascript style guide
方針
知識のある人は既にコードレベルの情報は発信しません。
望むのは正しいコードの書き方なので、それを引き続き探します。
前回の方針とは少し方向を変えて集合知に頼ってみます。
wikipedia
やはり困ったらwikipedia。 wikipediaは良いのですが、ページが細分化されている上英語じゃないと情報が少ない事が多いので案外盲点だったりします。
JavaScript syntax - Wikipedia, the free encyclopedia
github
コードや実装で困ったらgithubですが、なかなか丁度良いものは無いものです。
今回は幸運にもベストなのがありました。
日本語版もあるので、必要に応じて参照するのが良さそうです。
javascriptの情報を拾う場所
javascriptをちゃんと学習する気になったのでメモ
方針
最新の規格等に触れているブログ等を主軸に探します。
javascript draft
等で検索
文法
ECMAScript Syntax Grammar 6th Edition / Draft
ECMAScript Language Specification ECMA-262 6th Edition – DRAFT
ブログとか人とか
- azuさん
- teramakoさん
感想
javascriptの文法とか規格とかに言及している人はあまりみかけないなーといった印象です。
やはり外部のライブラリやサービスありきの言語なのでしょうか。
ひとまず文法を理解してからライブラリも徐々に拾っていきたいです。
ninjaのwindows環境ビルド
環境
windows8.1, visual studio community, python2.7
準備
PATHに追加
C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\bin C:\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\Tools
INCLUDEに追加
C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\INCLUDE C:\Program Files (x86)\Windows Kits\8.1\Include\um C:\Program Files (x86)\Windows Kits\8.1\Include\shared
LIBに追加
C:\Program Files (x86)\Windows Kits\8.1\Lib\winv6.3\um\x86 or x64 or arm C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\lib
実行
git clone git://github.com/martine/ninja.git ninja cd ninja python configure.py --bootstrap
ninja.exeができているはずです。
関数ポインタよりもstd::functionを使おう
書きやすさ
// 関数ポインタ void (*Func)(void); void (Foo::*Func2)(void); // std::function std::function<void(void)> Func; std::function<void(Foo*)> Func2;
これは慣れてないと両方読みづらいかもしれませんね。
慣れるとfunctionの方が型名、変数名といういつものルールに従っているので分かりやすくなります。
運搬性
void Test(){} // 関数ポインタ using ReturnFunction = void (*)(); ReturnFunction Func(){ return Test; } // C++14から以下の書き方もできる auto Func(){ return Test; } // std::function std::function<void()> Func(){ return Test; }
戻り値に関数ポインタを使う場合にはusingかtypedef宣言が必要になります。
autoを使えば省略できますが以下の事に注意する必要があります。
auto Func(){ return Test; } void Func2(ReturnFunction a){} void Func2(std::function<void()> a){} int main(){ auto a = Func(); // 関数ポインタ版の方が優先して呼ばれる Func2(a); }
部分適用
これは関数ポインタでは実現できないと思います。
void Int3(int, int, int){} int main(){ std::function<void(int, int, int)> a = Int3; // 3番目の引数を3で固定した引数が2個の関数を生成する std::function<void(int, int)> b = std::bind(a, std::placeholders::_1, std::placeholders::_2, 3); }
この機能はメンバ関数ポインタと合わせると更に強力で、メンバ関数にインスタンスを拘束して通常の関数の様に扱ったりできます。
class Foo{ public: void FooFunc(){} }; int main(){ Foo foo; std::function<void()> Func = std::bind(&Foo::FooFunc, &foo); // メンバ関数を通常の関数として呼べる Func(); }
初期値
// 関数ポインタ ReturnFunction a = nullptr; if(a != nullptr){ a(); } // std::function // 明示的初期化必要無し std::function<void()> a; // operator boolが設定してあるのでチェックも容易 if(a){ a(); }
ラムダ
std::functionならラムダの運搬も可能です。
std::function<void(void)> a = []{};
ただし、キャプチャにローカルオブジェクトを含む場合不定値になるので注意が必要です。