C++ CRTP-嵌套叶类类型的可见性
我想了解是否可以在基本CRTP类中使用叶CRTP类的嵌套类。下面的示例演示了这个问题C++ CRTP-嵌套叶类类型的可见性,c++,inner-classes,forward-declaration,crtp,C++,Inner Classes,Forward Declaration,Crtp,我想了解是否可以在基本CRTP类中使用叶CRTP类的嵌套类。下面的示例演示了这个问题 #include <iostream> using namespace std; template<class T> class A { protected: T* asLeaf(void) {return static_cast<T*>(this);} T const* asLeaf(void) const {retur
#include <iostream>
using namespace std;
template<class T>
class A
{
protected:
T* asLeaf(void)
{return static_cast<T*>(this);}
T const* asLeaf(void) const
{return static_cast<T const*>(this);}
public:
struct Inner
{int a = 10;};
void dispInner(void) const
{std::cout << asLeaf()->inner.a << std::endl;}
// I would like to use T::Inner in this class, e.g.
// typename T::Inner mvInnerA;
// However, I understand that it is not possible to
// use it in the form that is stated above. Thus,
// I am looking for any possible workarounds.
};
class B: public A<B>
{
public:
struct Inner: public A<B>::Inner
{int b = 20;};
protected:
friend A<B>;
B::Inner inner;
public:
void dispInner(void) const
{
A<B>::dispInner();
std::cout << asLeaf()->inner.b << std::endl;
}
};
int main()
{
B b;
b.dispInner();
return 0;
}
#包括
使用名称空间std;
模板
甲级
{
受保护的:
T*asLeaf(无效)
{返回静态_cast(this);}
T常数*asLeaf(void)常数
{返回静态_cast(this);}
公众:
结构内部
{int a=10;};
无效显示内部(无效)常量
{std::cout inner.a标准规定:
类在类说明符的结尾处被视为完全定义的对象类型(或完全类型)
因此,当您将a
专门化为a
时,B
不是一个完全定义的对象。因此,您不能期望能够从a
的定义中访问其成员或类型或任何内容(即使您可以从a
的成员方法的定义中回调派生类,但这完全是合法的,而不是CRTP习惯用法的目的)。
换句话说,当您这样做时:
typename T::Inner mvInnerA
您不能保证T
是一个完全定义的对象,这就是为什么会出现错误
有几个备选方案:
您可以将mvInnerType
定义为函数而不是类型,并将其用作工厂来创建T::inner
类型的对象:
[static] auto mvInnerA() {
return typename T::Inner{};
}
将其用作:
auto foo = A<B>::mvInnerA();
正确的形式取决于您是否将其设置为静态。
请注意,您仍然可以以某种方式使用隐藏类型,即使其名称不可访问:
using HiddenType = decltype(A<B>::mvInnerA());
HiddenType foo = A<B>::mvInnerA();
然后将其用作:
auto foo = A<B>::mvInnerA<>{};
autofoo=A::mvInnerA{};
因为类型T
是(让我说)通过U
间接使用的,只有当mvInnerA
被实例化时,您才不会有上面提到的问题。为此付出的代价是存在恼人的
以及可以将自定义类型传递给mvInnerA
如何使用CRTP模板参数的内部类型受到严重限制
在类模板定义本身的范围内没有任何用处。实例化模板时,需要完全定义类型B
,就像,它不是。但是,您可以在没有立即用类模板实例化的上下文中使用它,而类模板主要是A
虽然不能为B::internal
使用类型别名,但可以使用类型别名模板
template<class C>
using Inner = typename C::Inner
模板
使用Inner=typename C::Inner
哪个A
的成员函数可以用来避免typename B::internal
的冗长,而使用internal
一般的规则是基类不应该知道它的子类,您引入的是循环依赖,这是bad@lapinozz这就是他使用CRTP()的原因“这没什么错。@lapinozz-你是从动态多态性的角度思考的,它与CRTP的静态多态性完全正交。同样的“规则”不一定适用。我明白了,我的不好,但问题出在哪里?注释的代码似乎很好,错误是什么?@lapinozz感谢您的评论。我相信您在回答我问题的原始说明时所说的是正确的。但是,请参阅我在问题末尾所做的评论。谢谢很遗憾,我知道我出错的原因(请接受我的道歉,我会修改问题的定义)。但是,我正在寻找一种解决方法。哦,好吧,从这个问题来看,您似乎希望它能按原样工作。我不明白您要求的是另一种方法。对不起。@user1391279在我编辑答案之前,它能为您提供一种解决方案吗?换句话说,mvInnerA
不再是一种类型,而是一种返回ty的函数pe是T::internal
。您可以随时使用decltype
获取它,或者通过该函数创建该类型的实例。感谢您的评论。我将接受您的建议作为有效答案。@user1391279在回答中直接给出了两个备选方案。希望它们对您有效。感谢您上次的回复不幸的是,正如我在评论和问题定义中所提到的,我知道不可能在A
中定义成员变量B::internal
,以及为什么不能这样做。但是,我想了解是否有任何可行的解决方法可以请允许我在A
中使用B::internal
,因为我还没有考虑到自己。不幸的是,我不得不承认,我没有对这个问题提供充分的说明。
auto foo = A<B>::mvInnerA<>{};
template<class C>
using Inner = typename C::Inner