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

时间:2016-11-02 00:57:40

标签: c++ templates name-resolution

考虑以下示例:

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以及如何修复它,编译器为什么会出错?

3 个答案:

答案 0 :(得分:2)

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

其他选择是将T作为第二个参数传递。

答案 1 :(得分: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 {}

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

答案 2 :(得分:0)

由于this

,你无法做到这一点
  

在看到类别说明符的右括号[...]

之后,认为是一个类

除了少数例外情况,在您的情况下都不是有效的。
换句话说,当您尝试在基类中使用它来访问类型C时,必须将派生类视为未完全定义。

无论如何,您可以利用派生类是模板类的事实并执行此操作:

template <typename T>
class A;

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

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