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

C++1z クラステンプレートのテンプレート引数推論

C++

C++1zでは、クラステンプレートのテンプレート引数が推論されるようになります。

例として、冗長なコードになりがちなstd::lock_guardクラスを使用した以下のコードは、

std::mutex m1;
void f()
{
    std::lock_guard<std::mutex> lk(m);
}

C++1zでは以下のようにstd::lock_guardクラスのテンプレート引数を省略して書けるようになります:

std::mutex m;
void f()
{
    std::lock_guard lk(m);
}

この場合、mの型からstd::lock_guardクラスのテンプレート引数の型が推論されます。

C++1zでは、コンストラクタの引数からクラステンプレートのテンプレート引数が推論されます。std::lock_guardクラスの場合、先程のコンストラクタは以下のような宣言になっています:

template <class Mutex>
class lock_guard {
public:
    typedef Mutex mutex_type;
    explicit lock_guard(mutex_type& m);
};

このコンストラクタでは、その引数の型がそのままクラステンプレートのテンプレート引数になっているため、推論ができるようになっています。

ですが、変換コンストラクタのように、コンストラクタの引数から直接クラステンプレートのテンプレート引数を推論できない場合があります。イテレータ範囲を受け取るvectorのコンストラクタを考えます:

namespace std {
    // 簡略化したvectorとコンストラクタの宣言
    template <class T>
    class vector {
    public:
        template <class InputIter>
        vector(InputIter first, InputIter last);
    };
}

この場合は、引数の型InputIterからTを直接推論することはできません。このような場合には、ライブラリ側で推論の補助をする必要があります。推論補助は、クラステンプレートと同じスコープ (クラスの外)に、後置戻り値型 (trailing return type)と同じ構文で、コンストラクタに戻り値の型を明示します:

namespace std {
    template <class T>
    class vector {
    public:
        template <class InputIter>
        vector(InputIter first, InputIter last);
    };

    // 推論補助 (deduction-guide)
    template <class InputIter>
    vector(InputIter first, InputIter last)
        -> vector<typename iterator_traits<InputIter>::value_type>;
}

これでイテレータ範囲を受け取るvectorのコンストラクタでもクラステンプレートのテンプレート引数が推論できるようになり、以下のように書けるようになります:

std::list ls = {1, 2, 3};
std::vector v(ls.begin(), ls.end());

C++1z時点では、言語側の対応が入るのみで、標準ライブラリではクラステンプレートのテンプレート引数推論のための補助が入る予定はありません。

参照

お断り

この記事の内容は、C++1zが正式リリースされる際には変更される可能性があります。正式リリース後には、C++日本語リファレンスサイトcpprefjpの以下の階層の下に解説ページを用意する予定です。

編集履歴

  • 2016/10/25 12:47 : コメント欄でのk_satodaさんの指摘を受け、クラス内のコンストラクタに対して推論補助を記載していたところを、クラス外で推論補助するよう修正