C++03では、ひとつの引数をとるコンストラクタで変換コンストラクタ以外に対してはexplicit
を付ける、という慣習がありました (別の言い方をすると、パラメータ付き構築にexplicit
を付ける)。
C++11では、波カッコ構文による「一様初期化 (Uniform Initialization)」と初期化子リストがあるので、少し事情が異なります。C++11では、explicit
を付けたコンストラクタは、X x = {a, b, c};
のような代入演算子を伴うリスト初期化が禁止されます。
struct X { X(int, int) {} }; struct Y { explicit Y(int, int) {} }; int main() { X x {1, 2}; // OK Y y {1, 2}; // OK X x2 = {1, 2}; // OK // Y y2 = {1, 2}; // error }
そのため、1引数をとるコンストラクタにデフォルト引数をつけてデフォルトコンストラクタと実装をいっしょにすると、意図と違った挙動になる可能性があります。X x = {a, b, c};
構文を許可するかも含めて、任意のコンストラクタにexplicit
を付けるかどうかを検討しましょう。
struct A { A(int=0) {} }; struct B { explicit B(int=0) {} }; int main() { A a{}; // OK B b{}; // OK A a2 = {}; // OK // B b2 = {}; // error }
例として、string(int pos, int len)
みたいなコンストラクタは、explicit
にしたほうがいいですね。