1

次の例を検討してください。

template <typename T>
class A {
 private:
  typedef typename T::C C;
};

template <typename T>
class B : public A<B<T>> {
 public:
  typedef T C;
};

int main() {
  B<int> b;
}

GCC でコンパイルすると、次のエラーが発生します。

test.cc:5:23: error: no type named 'C' in 'B<int>'
  typedef typename T::C C;
          ~~~~~~~~~~~~^
test.cc:9:18: note: in instantiation of template class 'A<B<int> >' requested here
class B : public A<B<T>> {
                 ^
test.cc:15:10: note: in instantiation of template class 'B<int>' requested here
  B<int> b;
         ^

が定義されている場合にコンパイラがエラーを出すのはなぜB::Cですか? また、その修正方法は?

4

3 に答える 3

2

鶏と卵のパラドックスに陥っているため、できません。ベースの定義には、派生の定義に関する知識が必要であり、これにはベースの定義が完了する必要があります。あなたは単に代替案を考え出さなければなりません。1 つの例は、外部メタ関数を使用して、必要な型を必要な人に伝達することです。うまくいけば、それがベースのメンバーの定義のどの部分にも含まれていないか、おそらくあなたはうんざりしています.

別の方法として、T を 2 番目のパラメーターとして渡すこともできます。

于 2016-11-02T01:05:06.480 に答える
2

この時点で、

class B : public A<B<T>> {

… クラスBは不完全です。クラスAはその中を見ることができません。

内部のC型定義Bは、内部のそのポイントからアクセスできますBBクラス定義内の関数定義をクラスの後に配置するための省略形と見なすことができるため、関数本体内でも使用できます。しかし、不完全なクラスには、外部から見ると何も含まれていません。外部コードができることは、ポインタと参照を形成し、クラスをテンプレート引数として使用することだけです。

template< class C >
using Ungood = typename C::Number;

struct S
{
    void foo() { Number x; (void) x; }      // OK
    Ungood<S> uhuh;                         //! Nyet.

    using Number = double;
};

auto main() -> int {}

デザインを変更することでコードを修正できます。最も明白なのは、型を別のテンプレート引数として渡すことです。しかし、達成しようとしているものによっては、現在持っている継承が実際には必要ないか、役に立たない場合があります。

于 2016-11-02T01:05:32.127 に答える
0

このため、それを行うことはできません:

クラスは、そのクラス指定子の右中括弧が表示された後に定義されたと見なされます [...]

そしていくつかの例外がありますが、あなたのケースではどれも有効ではありません。
つまり、派生クラスを基本クラスで使用して type にアクセスしようとするときは、派生クラスが完全に定義されていないと見なす必要がありますC

とにかく、派生クラスがテンプレート クラスであるという事実を利用して、次のことを行うことができます。

template <typename T>
class A;

template <template<typename> class D, typename T>
class A<D<T>> {
private:
    using C = T;
};

おわかりのように、プライマリ テンプレート クラスの定義を行っていないため、テンプレート クラスの特殊化のみを使用できます。
これがOPの実際のケースであるかどうかはわかりませんが、質問の例ではそうです。

于 2016-11-02T07:19:15.497 に答える