template <typename T>
class Base
{
private:
typename T::B c;
};
class A : public Base<A>
{
public:
class B;
};
这样的事情是否可能? VC ++ 2013表示B不是A的成员。
答案 0 :(得分:6)
故事
如直接针对您的问题的评论中所说,您想要完成的内容是不可能的,因为引用不完整类型(T = A
在Base
内是非法的1}})。
替代方案
CRTP案例中的常见解决方法是使用trait
来表示Derived
和Base
中应该可用的成员,但这些成员不应声明/定义在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
仅包含指定上述嵌套类的类型的别名。现在Base
从Nested
读取此类型,并定义此类型的数据成员。
在我们专门针对A
和Impl
之前,我们需要声明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;
};
具有完全相同的问题。