C++プログラマ キャスブログ
[C++11]auto変数を使おう!ただし慎重に... 2014年11月22日01:15:32
auto変数は型推論をして自動的に型を割り振ってくれる非常に便利なものです。
1 2 3 auto i = 10; //int型 auto f = 10.0f; //float型 auto d = 10.0; //double型
一見便利なのですが、プログラマ自身は型を知っておく必要があるので 元に戻すには脳内コンパイルおよび目グレップを行わなくてはなりません。 読み手が困るだけなので、乱用はオススメしません。 効果的な使い方は型が自明でかつ、その場で利用するものが好ましいでしょう。 私が利用する場合は、イテレータやラムダ式での利用のみです。
1 2 3 4 5 6 7 #include <array> // std::arrayを使うために必要なヘッダー std::array<int,5> arr = { 1, 2, 3, 4, 5 }; for( auto i=arr.begin(); i != arr.end(); ++i ) { // 何かしらの処理 }
1 2 3 auto lambda = [](int i){ return i; }; lambda( 10 );
autoの注意点です。 型推論時に付いていれば別ですが、constや参照は自動で付けてくれません。 その辺りは手動で行わなくてはならないので、意識する必要があります。 困る事例はforeachを利用した場合です。
1 2 3 4 5 6 7 8 // 注意:これはダメなコードです #include <array> // std::arrayを使うために必要なヘッダー std::array<int,5> arr = { 1, 2, 3, 4, 5 }; for( auto i: arr ) { i = 10; // 参照ではないので値が書き変わりません。 }
正しくはこうです。
1 2 3 4 5 6 7 #include <array> // std::arrayを使うために必要なヘッダー std::array<int,5> arr = { 1, 2, 3, 4, 5 }; for( auto& i: arr ) { i = 10; }
コンテナの中身がオブジェクトの場合には参照をつけておかないと コピーコンストラクタが毎回走ってしまう悲惨なことになります。 細心の注意を払わなければならない機能なのでもろ手を挙げてオススメはできないですね… 余談ですがauto変数って始めて聞いたとき「記憶クラス」の事だよねーって一瞬本気で思いました。 [記憶クラス] auto: 自動変数(ローカル変数) ※省略するとこれになる extern: 外部変数 static: 静的変数 register: レジスタ変数 ※可能な限りレジスタを使う ちなみにintの変数宣言をフルスペック(?)で書くとこんな感じになります。
1 auto signed int i;
同じキーワードで紛らわしいと思ったものです。
[C++11]ラムダ式(無名関数、匿名関数)とstd::function 2014年11月21日00:10:24
ラムダ式とは簡単に言えば関数内に作成できる一時的な関数です。 基本的な書き方はこちら
1 2 // [キャプチャ指定※後述](引数) -> 戻り値の型{ 処理; } [](int a, int b) -> int { return a+b; };
呼び出し方は普通の関数と同じ呼び方です。
1 2 // resultには3が入ります。 int result = [](int a, int b) -> int { return a+b; }( 1, 2 );
上記のような使い方は全く意味がありませんね。 処理をそのまま書いておけって感じです。 そこで関数ポインタに入れることによって効力を発揮するのですが 無名関数、匿名関数といいつつも関数ポインタには代入出来ません。 な、なんてこったー!! ということでstd::functionを利用しましょう。
1 2 3 4 5 6 7 8 9 10 #include <functional> //std::functionを利用するためのヘッダー // 残念ながら関数ポインタには代入できません。 // int (*lambda)(int,int) = [](int a, int b) -> int { return a+b; }; // std::functionを使いましょう。 std::function< int(int,int) > lambda = [](int a, int b) -> int { return a+b; }; // 呼び方 resultには3が入ります int result = lambda(1,2);
お待たせしました。キャプチャについての説明です。 ラムダ式は外側のスコープの変数にアクセスできます。 その機能のことをキャプチャと呼びます。 書き方は先ほどの[]の中に指定子を書きます。 [=] 外側のスコープの変数はコピーとして扱います。 [&] 外側のスコープの変数は参照として扱います。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 #include <functional> //std::functionを利用するためのヘッダー int c = 100; // 外側の変数をコピーとして扱う[=] std::function< int(int,int) > lambda = [=](int a, int b) -> int { return a+b+c; }; // resultには103が入ります int result = lambda(1,2); // 外側の変数を参照として扱う[&] // cは200に置き換わります。 std::function< void() > write = [&]() -> void { c=200; }; write(); // cを200に書き換えたのでresultには203が入ると勘違いしがちですがlambda作成時の // 変数cの100がコピーされた状態で残っているので103となります。 // ここを203としたい場合にはlambdaの指定を[&]参照にしておく必要があります。 result = lambda(1,2);
[=]と[&]は外側全ての変数に対して指定するキーワードですが 安全性を確保する為に個別に指定も可能です。 []内に使用する変数名をそのまま書けばOKです。 何も付けなければ代入となり&を付けると参照になります。
1 2 3 4 5 6 7 8 9 10 #include <functional> //std::functionを利用するためのヘッダー int c = 100; int d = 200; // [c,&d] cは代入 dは参照 std::function< int(int,int) > lambda = [c,&d](int a, int b) -> int { return a+b+c+d; }; // resultには303が入ります int result = lambda(1,2);
余談ですが、キャプチャに対してconstを付けたいと思ったのは私だけでしょうか 例えばこんな感じにです。 [const &] ラムダ式の中で書き換えが行われない事が保証できて安全だと思うのです。 現在の仕様では出来ないようですが、将来的な改善に期待したいです。
[C++11]イテレータとはおさらばforeach 2014年11月20日07:46:02
コンテナを回すのに長ったらしいイテレータとはもうおさらばです。 C++11からはforeachを使いましょう!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 #include <vector> // std::vectorを使うために必要なヘッダー #include <cstdio> // printfを使うために必要なヘッダー std::vector<int> vec = { 1, 2, 3, 4, 5 }; // イテレータの場合 for( std::vector<int>::iterator i=vec.begin(); i != vec.end(); ++i ) { printf( "%d\n", *i ); } // foreachの場合 // for( 要素の型 : コンテナ ) for( int i : vec ) { printf( "%d\n", i ); }
普通の配列にも使えます。
1 2 3 4 5 6 7 8 #include <cstdio> int arr[] = { 1, 2, 3, 4, 5 }; for( int i : arr ) { printf( "%d\n", i ); }
中身を書き換えるなら参照に
1 2 3 4 5 6 int arr[] = { 1, 2, 3, 4, 5 }; for( int& i : arr ) { i = 0; }
コンテナの中身がオブジェクトの場合は参照をつけておかないと コピーコンストラクタが走るのでご注意を
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 #include <string> // std::stringを使うために必要なヘッダー #include <cstdio> // printfを使うために必要なヘッダー std::string arr[] = { "a", "b", "c", "d", "e" }; // コピーコンストラクタが走る残念な事例 for( std::string i : arr ) { printf( "%s\n", i.c_str() ); } // これでOK for( std::string& i : arr ) { printf( "%s\n", i.c_str() ); } // 読み取り専用であればconstを忘れずに for( const std::string& i : arr ) { printf( "%s\n", i.c_str() ); }
カテゴリ

リンク
C++11のコードを
試すのに便利です。
http://ideone.com/

同人ゲームを
製作している知人
sorcery

にほんブログ村 IT技術ブログ C/C++へ
にほんブログ村


C++ ブログランキングへ

ゲームダウンロード DefenceTri