如何引用作为模板参数传递的派生类中定义的类型



考虑以下示例:

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定义和如何修复它?

此时,

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

白马王子;B是不完全类。A班不能往里面看

B中的C类型定义可以从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 {}

您可以通过更改设计来修复代码。最明显的方法是将类型作为单独的模板参数传递。但是,根据您想要实现的目标,您当前拥有的继承可能不是真正需要的,甚至不是有用的。

你不能,因为你处于先有鸡先有蛋的悖论中。基的定义需要对基的定义有一定的了解,这就需要对基的定义来完成。你只需要想出一个替代方案。一个例子是使用外部元函数将所需的类型传递给需要它的人。希望这不在base成员定义的任何部分中,否则你可能会完蛋。

你不能这样做,因为:

在类说明符的右大括号出现后,类被认为是定义的[…]

还有一些例外,在你的情况下没有一个是有效的。
换句话说,当您试图在基类中使用派生类访问类型C时,必须考虑派生类没有完全定义。

无论如何,您可以利用您的派生类是模板类的事实并这样做:

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

你可以看到,我没有给出主模板类的定义,因此只能使用模板类的专门化。
不确定这是OP的真实情况,但它是在问题中的例子中的情况。

最新更新