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

C++1z using宣言のパック展開

C++

using宣言 (using-declaration) には、2つの用途があります:

  1. メンバ関数を、基本クラスと派生クラスでオーバーロードする
  2. 識別子の名前空間を省略できるようにする

これらusing宣言に指定する識別子が、ひとつだけでなく、カンマ区切りで複数指定できるようになります。

メンバ関数のusing宣言

C++11で可変引数テンプレートが導入されたことにより、派生クラスを定義する際に、基本クラスのリストを受け取ってまとめて多重継承できるようになりました。その際、using宣言の対象をひとつしか指定できなかったため、基本クラスと派生クラスでメンバ関数オーバーロードをする場合、以下のように、再帰テンプレートによってusing宣言するという回避策をとる必要がありました:

#include <iostream>
#include <iomanip>
#include <utility>

template <typename T, typename... Ts>
struct Overloader : T, Overloader<Ts...> {
    using T::operator();
    using Overloader<Ts...>::operator(); // 回避策:再帰でusing宣言
};

template <typename T> struct Overloader<T> : T {
    using T::operator();
};

template <typename... Ts>
constexpr auto make_overloader(Ts&&... ts)
{
    return Overloader<Ts...>{std::forward<Ts>(ts)...};
}

int main()
{
    auto o = make_overloader([] (auto a) {std::cout << a << std::endl;},
                             [] (float f) {std::cout << std::scientific << f << std::endl;});

    o("hello");
    o(1.2f);
}

C++1zでusing宣言に複数の識別子を指定できるようになることで、これがより簡潔に書けるようになります。

#include <iostream>
#include <iomanip>
#include <utility>

template <typename... Ts>
struct Overloader : Ts... {
    using Ts::operator()...; // C++1z
};

template <typename... Ts>
constexpr auto make_overloader(Ts&&... ts)
{
    return Overloader<Ts...>{std::forward<Ts>(ts)...};
}

int main()
{
    auto o = make_overloader([] (auto a) {std::cout << a << std::endl;},
                             [] (float f) {std::cout << std::scientific << f << std::endl;});

    o("hello");
    o(1.2f);
}

名前空間を省略するためのusing宣言

using宣言のパック展開は、主な目的は先に示したメンバ関数オーバーロードですが、副次的に、名前空間を省略するためのusing宣言も、カンマ区切りで複数指定できるようになります。

#include <iostream>

int main()
{
    using std::cout, std::endl; // C++1z

    // C++14まで
    // using std::cout;
    // using std::endl;

    cout << "hello" << endl;
}

複数をカンマ区切りで指定できるだけなので、using std::cout, endl;のように2つ目以降の指定で名前空間を省略するような書き方はできません。

参照

お断り

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