読者です 読者をやめる 読者になる 読者になる

コンストラクタに用途別の名前を付ける

C++

最近のC++標準ライブラリとBoostのちょっとした流行りな気がしますが、タグディスパッチのタグをユーザーに明示的に指定させることで、関数オーバーロードを容易にする方法がいくつかの場所でとられています。

たとえば、Boost.Containerのvectorには、以下のコンストラクタがあります。

// タグの定義
struct default_init_t {};
constexpr default_init_t default_init {};

// vectorのコンストラクタ
vector::vector(size_type, default_init_t);

// 3要素の配列を用意し、各要素の値を未初期化状態にする
vector<T> v(3, default_init);

この場合、単に3という1引数を渡すだけだと値初期化したリサイズ操作になりますが、default_initというタグを付けることによって「未初期化状態にする」というプログラマの意図を付加しています。

通常の関数だとこのような場合、別名の関数を用意して用途を分けますが、コンストラクタは名前がないのでこういったタグ付けが行われています。

C++標準ライブラリにもいくつかタグをユーザーが渡す場所があります。たとえば、ミューテックスを関数内でロック取得し、ロックを手放す操作を行うためのlock_guardクラスのコンストラクタがそうです。

mutex m;

void f()
{
    m.lock();

    // ロック取得済みのミューテックスを渡して、
    // スコープ終了時に自動的にロックを手放す
    lock_guard<mutex> lk(m, adopt_lock);
    // …共有リソースに対する操作...

} // ここでm.unlock()がlock_guardのデストラクタによって自動的に呼ばれる

このようなタグ付けは、コンストラクタオーバーロードに意味を持たせる目的に使えますので、便利に使っていい技法ではないかと思います。タグはおそらく、第1引数にするのがいいですね。意味を持たせてその用途の引数を渡す、という順番にすることでルールがわかりやすくなるので。