从模板类Base <a> so that Base</a> <a> can use A::B?</a>派生A类

时间:2014-03-24 12:52:38

标签: c++

template <typename T>
class Base
{
private:
    typename T::B c;
};

class A : public Base<A>
{
public:
    class B;
};

这样的事情是否可能? VC ++ 2013表示B不是A的成员。

2 个答案:

答案 0 :(得分:6)

故事

如直接针对您的问题的评论中所说,您想要完成的内容是不可能的,因为引用不完整类型T = ABase内是非法的1}})。


替代方案

CRTP案例中的常见解决方法是使用trait来表示DerivedBase中应该可用的成员,但这些成员不应声明/定义在Base

尽管这并不等同于你想要实现的目标,但它与它非常接近,并且遵循一定的等效语义。

template<class> struct some_trait;       // primary template

template <class T>
struct A : some_trait<T> {               // (1)
  typename some_trait<T>::C a;
};

template<> struct some_trait<struct B> { // (2)
  class C { };
};

struct B : A<B> {                        // (3)
  C b;
};

int
main (int argc, char *argv[])
{
  B a; // legal
}

为什么办公室工作?

缩短它;我们不再尝试访问不完整类型的内部。

some_trait<B>在标记为(2)的定义(即专业化)之后是一个完整的类型,因此(1)(3)可以使用它导致任何问题。

答案 1 :(得分:1)

我会这样(live example):

template<typename T> struct Impl;
template<typename T> struct Nested;

template <typename T>
class Base
{
private:
    typename Nested<T>::type c;
};

struct A;

template<> struct Impl<A>   { class B { }; };
template<> struct Nested<A> { using type = typename Impl<A>::B; };

struct A : Base<A>, Impl<A>
{
    //...
};

此处,课程Impl包含A的不依赖于Base的部分,即嵌套类B。因此,A现在同时派生Base<A>Impl<A>

Nested仅包含指定上述嵌套类的类型的别名。现在BaseNested读取此类型,并定义此类型的数据成员。

在我们专门针对AImpl之前,我们需要声明Nested。我们在定义A之前需要这些专业化,因为此时Base<A>已实例化,这需要Nested<A>完成,这反过来要求Impl<A>完成。< / p>

Philip's answer的主要区别在于责任更加分散:

  • Base没有得到任何东西,因此被污染的可能性更小。我们只将其数据成员的类型更改为typename Nested<T>::type,就是这样。

  • Nested是纯粹的特质。它只定义了别名type,就是它。

  • Impl是一个实现类。它包含嵌套类B的定义,或者可能包含不依赖于Base的任何其他内容。


顺便说一句,Stroustrup的第4版The C++ Programming Language在第771页上有以下代码:

template<typename N>
struct Node_base : N::balance_type { };

template<typename Val, typename Balance>
struct Search_node : Node_base<Search_node<Val, Balance> >
{
    using balance_type = Balance;
};

具有完全相同的问题。

相关问题