不思議なことに繰り返されるテンプレート パターンを使用すると、基本クラスから参照しようとした場合にのみ、派生クラスに属する typedef を参照できません。gcc は文句を言いno type named 'myType' in class Derived<...>
ます。これは、typedef、テンプレート、および不思議なことに繰り返される関係を使用して他の方法で可能なことと矛盾しているようです。
検討:
/* crtp.cpp */
#include <iostream>
using namespace std;
// case 1. simple.
class Base {
public:
typedef int a_t;
a_t foo;
};
class Derived : public Base {
a_t bar;
};
// case 2. template.
template<typename T>
class tBase {
public:
typedef T b_t;
T foo;
};
template <typename T>
class tDerived : public tBase<T> {
typename tBase<T>::b_t bar;
};
// case 3. curiously recurring.
template <typename T, typename D>
class tCuriousBase {
public:
typedef T c_t;
c_t foo;
};
template <typename T>
class tCuriousDerived : public tCuriousBase<T,tCuriousDerived<T> > {
typename tCuriousBase<T,tCuriousDerived<T> >::c_t bar;
};
// case 4. curiously recurring with member reference.
template <typename T, typename D>
class tCuriousMemberBase {
public:
T foo;
T get() {
return static_cast<D*>(this)->bar;
}
};
template <typename T>
class tCuriousMemberDerived : public tCuriousMemberBase<T, tCuriousMemberDerived<T> > {
public:
T bar;
tCuriousMemberDerived(T val) : bar(val) {}
};
// case 5. curiously recurring with typedef reference.
template <typename T, typename D>
class tCuriousTypeBase {
public:
typedef T d_t;
d_t foo;
typename D::c_t baz;
};
template <typename T>
class tCuriousTypeDerived : public tCuriousTypeBase<T, tCuriousTypeDerived<T> > {
public:
typedef T c_t;
typename tCuriousTypeBase<T,tCuriousTypeDerived<T> >::d_t bar;
};
// entry point
int main(int argc, char **argv) {
Derived::a_t one = 1;
tDerived<double>::b_t two = 2;
tCuriousDerived<double>::c_t three = 3;
double four = tCuriousMemberDerived<double>(4).get();
tCuriousTypeBase<double, tCuriousDerived<double> >::d_t five = 5;
// tCuriousTypeDerived<double>::d_t six = 6; /* FAILS */
cout << one << endl;
cout << two << endl;
cout << three << endl;
cout << four << endl;
cout << five << endl;
// cout << six << endl;
}
(1) から、typedef は実際にベースから派生に継承されていることがわかります。基本クラスで宣言された typedef は、派生クラスを介してアクセスできます。
(2) から、両方のクラスがテンプレートである場合でも、これは真であることがわかります。
(3) から、この typedef 継承は、不思議なことに繰り返されるテンプレート関係の存在下でも存在できることがわかります。の宣言で、派生クラスを介してベースの typedef を参照しますthree
。
(4) から、派生クラスのメンバー変数は基底クラスから容易にアクセスできることがわかります。
(5) から、テンプレート パラメーターで定義された typedef にアクセスできることがわかります (これはfive
、継承によって関連付けられていない型を使用して宣言するときに機能します)。
ただし、(6) でテンプレート パラメーターを派生クラスにするとすぐに、派生クラスのメンバー変数と同じように適切に定義されているように見えても、突然 typedef にアクセスできなくなります。
どうしてこれなの?