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

你不能,因为你处于鸡蛋与鸡蛋的悖论中。基的定义需要知道派生的定义,而派生的定义需要基的定义来完成。你只需要想出一个替代方案。一个例子是使用外部元函数将所需类型传达给任何需要它的人。希望这不在基地成员定义的任何部分,否则您可能会被搞砸。

另一种选择是将 T 作为第二个参数传递。

于 2016-11-02T01:05:06.480 回答
2

在此刻,

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

……课程B不完整。类A不能看里面。

里面的C类型定义B可以从里面的那个点访问B,等等。它也可以在函数体中使用,B因为您可以将类定义中的函数定义视为将其放在类之后的简写。但是从外部看,一个不完整的类不包含任何内容:外部代码所能做的就是形成指针和引用,并将类用作模板参数。

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

因为这个,你不能这样做:

一个类在其类说明符的右大括号被看到后被认为是定义的 [...]

还有一些例外,在您的情况下均无效。
换句话说,当您尝试在基类中使用派生类来访问类型时,您必须考虑到派生类没有完全定义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 回答