C++ 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

我想了解是否可以在基本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
        {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