using宣言 (using-declaration) には、2つの用途があります:
- メンバ関数を、基本クラスと派生クラスでオーバーロードする
- 識別子の名前空間を省略できるようにする
これら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();
};
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()...;
};
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;
cout << "hello" << endl;
}
複数をカンマ区切りで指定できるだけなので、using std::cout, endl;
のように2つ目以降の指定で名前空間を省略するような書き方はできません。
参照
お断り
この記事の内容は、C++1zが正式リリースされる際には変更される可能性があります。正式リリース後には、C++日本語リファレンスサイトcpprefjpの以下の階層の下に解説ページを用意する予定です。