ゆとりーなの日記

日記的な事を書いて行くと思はれる

暗黙の変換〜

なんか久々にドットを打ちました。

バハムートラグーンのヨヨ様ですね。このゲームやってないのですが、レビューを読んだだけでトラウマ余裕でした。まぁでも人間の女の子ってこんなものなんだろうなぁとか思ってしまうくらいには以下略です。しかし杖はちゃんと直線引いとくべきだったかもですが面倒なんでもういいです。はい。
で、今日はこんな話がしたかったのではなくexplicitなコンストラクタ、0x環境ではどういう基準でつけるんですかねってのが気になったって話です。
現行C++ではexplicitは一引数を取るコンストラクタ(デフォルト引数がある場合はこの限りではない)を持つクラスに於いて暗黙の型変換を防ぐという重要な役割を持っており、基本的には暗黙の型変換は避けたいことが多いので、一引数コンストラクタは殆どの場合でexplicitになるかと思います。
C++0xでは一様な初期化構文が導入され、コンストラクタを持つクラスでも{}での初期化が出来るようになります。これでC互換の構造体と同様な初期化手段がC++なクラスにも晴れて提供されることになります。さて、ここで問題が出てきます。explicitをコンストラクタに付けると、{}による初期化を禁止することが出来ます。つまりC++0xでは複数引数のコンストラクタにexplicitを付けることにも意味があるわけです。こうなってくると何時コンストラクタにexplicitを付けるべきかがよく分からなくなってきます。
先ず一番困るのは一引数の場合です。

struct basic_foo {
  int i;
};

struct cpp_foo1 {
  cpp_foo(const int i) : i_(i) {}
  int i_;
};

struct cpp_foo2 {
  explicit cpp_foo(const int i) : i_(i) {}
  int i_;
};

int main() {
  foo f1 = 0; // 1駄目
  foo f2 = {0};
  cpp_foo1 = 0;
  cpp_foo1 = {0};
  cpp_foo2 = 0; // 駄目
  cpp_foo2 = {0}; // 駄目
  return 0;
}

取り敢えずC互換構造体、explicitなしなコンストラクタを持つ構造体、ありなコンストラクタを持つ構造体を用意してみましたが、どれも出来る初期化構文がバラバラです。explicitを付けないのが一番自由度がありますが、ありすぎて数値単体から暗黙の変換が効いてしまうのでこれは避けたいところです。しかしこれを防ぐためにexplicitをつけると{}で初期化が出来なくなるというのが悲しいです。{}があれば流石に意図せぬ暗黙の型変換が行われている感じがそれほどしない気がするのでそれほど問題ない気はします。
で、複数引数を取るコンストラクタでは構造体的様相を呈すもの、たとえば座標管理する構造体とか以外では案外explicitをつけておくのがいいのかもしれないですね。データを運ぶ構造体だけどコンストラクタがあるだけで{}で初期化できないのは嫌だっていうのはありますが、普通のクラスは明示的にクラス名(引数)で初期化したほうがいいのかもしれません。寧ろこっちの方が自然な気がします。
C++0x環境ではどういう基準でコンストラクタにexplicitを付けるのがいいんですかね。