名前が分からない基底クラスでも Inheriting constructors したい
さて、C++11 で新しく追加された Inheriting constructors という機能なんですが、これは次のように使うことが出来ます。
struct base{ constexpr base(int value) : value(value){} constexpr base(int value1, int value2) : value(value1 + value2){} int value; }; struct X : base{ // 基底クラスのコンストラクタを派生クラスで使用できるように定義 using base::base; }; // 基底クラスのコンストラクタが使用出来る constexpr X x{ 42 }; constexpr X x2{ 23, -9 }; static_assert(x.value == 42, ""); static_assert(x2.value == 23 + -9, "");
こんな感じで using することで基底クラスのコンストラクタを派生クラスで使用することができます。
C++03 のように派生クラスで基底クラスのコンストラクタを明示的に定義する必要はありません。
継承を多用している場合、結構欲しいと思っていた機能ですね。
また、下記のようにテンプレートも使用することができます、
struct base1{ constexpr base1(int value) : value(value){} int value; }; struct base2{ constexpr base2(int value1, int value2) : value(value1 + value2){} int value; }; template<typename T> struct X : T{ using T::T; }; // テンプレートに渡したクラスのコンストラクタが使用出来る constexpr X<base1> x{ 42 }; constexpr X<base2> x2{ 23, -9 }; static_assert(x.value == 42, ""); static_assert(x2.value == 23 + -9, "");
[問題]
さて、次のようにテンプレート型によって基底クラスを変更したい場合があります。
template<bool B> struct X : std::conditional<B, base1, base2>::type{ // どっちを定義すればいいのか分からない // using base1::base1 // using base2::base2 }; constexpr X<true> x{ 42 }; constexpr X<false> x2{ 23, -9 };
このような場合、どうやって Inheriting constructors を定義すればいいのか分からなかったので、簡単なラッパークラスを作って対応してみました。
[ソース]
#include <type_traits> template<typename Base> struct inheriting_constructor : Base { using Base::Base; }; struct base1{ constexpr base1(int value) : value(value){} int value; }; struct base2{ constexpr base2(int value1, int value2) : value(value1 + value2){} int value; }; template<bool B> struct X : // inheriting_constructor を継承する inheriting_constructor< typename std::conditional<B, base1, base2>::type > { // inheriting_constructor を指定して using using inheriting_constructor< typename std::conditional<B, base1, base2>::type >::inheriting_constructor; }; int main(){ constexpr X<true> x{ 42 }; constexpr X<false> x2{ 23, -9 }; static_assert(x.value == 42, ""); static_assert(x2.value == 23 + -9, ""); return 0; }
こんな感じ。
メタ関数以外にも decltype を使って継承した場合にも使えそうですね。