Effective Modern C++勉強会#2 行ってきた

まとめページ
Effective Modern C++勉強会#2 : ATND

Effective Modern C++: 42 Specific Ways to Improve Your Use of C++11 and C++14

Effective Modern C++: 42 Specific Ways to Improve Your Use of C++11 and C++14

近日中にC++を使えるようになっていなければならないという状況におかれている昨今、一番新しいことやってるぽい本の勉強会に行けば雰囲気もつかめるだろうと思って参加。*1

参加してみてやっぱり基礎知識が足りていないので入門書が必要だと痛感する次第。
いい本ないかしら…。

以下メモ書き

item 7 Distinguish between () and {} when creating objects @talos208

初期化子の{}と()の違いを知りましょう。

C++11の初期化方法はいろいろある。

  • int z{0}; == int z = {0};

初期化時の=は代入ではない。 代入ではなく、コピーコンストラクタが呼ばれる。

インスタンスができてからの代入は代入になる。

統一的な初期化構文

std::vector v{1,2,3}; // C++11から導入された、複数要素の代入

いままで

class Widget {  
    …   
private:  
    int x{0};  
    int y = 0;  
    int z(0); // 関数のプロトタイプと解釈されてエラー  
}  

コピー出来ないオブジェクト

例:std::atmicには"="が使えない

std::atomic<int> ai0{0};  
std::atomic<int> ai1(0);  
std::atomic<int> ai2 = 0; // エラー  

// "{}"内ではnarrowingが禁止  
double x,y,x;  
int sum1{ x + y + z}; // エラー 情報が落ちる  
int sum2( x + y + z); // 暗黙でintになる  

もっとも厄介な解析

Widget w1(10);

Widget w2(); // widget型を返す関数w2と解釈される  
Widget w3{}; // 引数なしの変数初期化  
Widget w4;   // これだとどうなる?  

std::initializer_listとコンストラクタ

コンストラクタシグネチャによっては全く直観的ではない挙動を引き起こすおそれがある。

Widget(int i, bool d);  
Widget(int i, double d);  
Widget(std::initializer_list<long double> il); // これが曲者  

Widget w2{10, true} // 3番目のコンストラクタが呼ばれる。  
Widget w4{10, 5.0} // 3番目のコンストラクタが呼ばれる。  

クラスの提供者はstd::initializer_list<>を引数を御付コンストラクタを加えるときに熟考がいる。

正直ここまで複雑な挙動を理解できる気がしない…。

item8 Prefer nullptr to 0 and NULL

C++はポインタのところに0があったらnullptrに解釈されるが、リテラルの0はintであってポインタではない。
NULLはint以外でも使えるが、intの0と問題は同じ
リテラルNULLに決まった型はない。
nullptrの型はstd::nullptr_tとして、すべてのポインタ型として変換可能

  1. void f(int);
  2. void f(bool);
  3. void f(void*);

f(0) // 1が呼ばれる
f(NULL) // 何が呼ばれるかわからないが、3が呼ばれることはない
f(nullptr) // 確実に3が呼ばれる

item9 Prefer alias declarations to typedefs

ポインタに関連する別名をつけるときは、using句を使おう!
templateを宣言するときとかいいよ。
typedefはコンパイラにやさしくない。

<type_traits>

C++14だとtypename_tでusing版が提供される。 自分でやりたい場合、テンプレートの特殊化には耐えられない?

item10 Prefer scoped enums to unscoped enums

従来のenum名前空間がグローバル。
enumで使われた定数名は変数名に使えなかったりする。
enum class Colorとかやると、変数名にはパースされない。

列挙型を型として識別されて、変数に変な値は入れたり、比較はコンパイルで怒られる。
Class enumはクラスなので前方宣言できる。

javaとは違って定数はただの定数、メソッドを持ったりはできない。残念…。

item11 Prefer deleted functions to private undefined ones.

c++98では自動生成されたくない関数は未定義privateメンバ関数を宣言していた。
c++11においてはdeletedを使うと、コンパイル/リンク時にエラー検出してくれる。
暗黙の型変換で意図しないやつを関数呼び出しで禁止される。(オーバーロードしてやる)
特定のtemplate特殊化を禁止できる。
=> ホワイトリスト的にはできないのかな?
=> なんでもとれる関数templateをdeleteとしておいて、必要なものだけ定義するという方法で実現できるぽい。

*1:C++はbetter C以外の使い方を分かってない…