是否有没有前向声明的不完整嵌套类型的语法?

Is there a syntax for incomplete nested type without a forward declaration?

以下程序产生诊断错误。

#include <memory>
class Containing {
    // class Nested;                 // [1]: This line seems required.
    typedef std::shared_ptr<class Nested> Ptr;
    class Nested {
        Ptr & ptr ();
        void foo (const Ptr &p) {
            p->ptr() = ptr()->ptr(); // [2]: Error here without [1]
        }
    };
};
int main () {}

生成的诊断是:

prog.cpp:8:14: error: invalid use of incomplete type 'class Nested'
             p->ptr() = ptr()->ptr();
              ^
prog.cpp:4:35: error: forward declaration of 'class Nested'`
     typedef std::shared_ptr<class Nested> Ptr;
                                   ^

但是,如果我取消注释前向声明,编译就会成功。我相信原因是 Nested 在用于 shared_ptr<> 时被假定为不嵌套。如果是这样,是否有一种语法可以让 shared_ptr<> 知道 Nested 是嵌套的,没有前向声明?类似于:

class Containing {
    typedef std::shared_ptr<class Containing::Nested> Ptr;
    //...

本题用一个最小的例子来说明问题。实际结构如下:

class Containing {
    typedef std::shared_ptr<class NestedInterface> Ptr;
    class NestedObject {
        Ptr ptr_;
        //...
    };
    class NestedInterface {
        virtual NestedObject & object () = 0;
        void foo (const Ptr &p) {
            // ...
        }
        //...
    };
    class NestedType1 : NestedInterface {
        NestedObject obj_;
        NestedObject & object () { return obj_; }
        //...
    };
    class NestedType2 : NestedInterface {
        Containing &c_;
        NestedObject & object () { return c_.nested_object_; }
        //...
    };
    //...

你应该把那个声明 class Nested; 放在那里。

声明PtrNested关系是先有鸡还是先有蛋的问题,前向声明才是正确的处理方式。

编译器需要知道标记 Nested 是一个 class,而不是其他东西。当编译器达到 Ptr 时,该信息就足够了,class 的详细信息尚不相关。然后编译器到达完整的 Nested 声明,详细信息可用于 class.

的所有未来使用

不,没有。

但是,您根本不需要避免前向声明。这有效:

class Containing {
    class NestedInterface;
    typedef std::shared_ptr<NestedInterface> Ptr;
    class NestedObject {
        Ptr ptr_;
        //...
    };
    class NestedInterface {
        // ...
    };
};

有时 classes 内部的交叉依赖性可能会使这很难做到。在这种情况下,您需要做的就是避免定义内联引用 classes,而是声明 other classes 外联,像这样:

class Containing {
    class NestedInterface;
    class NestedObject;
    typedef std::shared_ptr<NestedInterface> Ptr;
};
class Containing::NestedObject {
    Ptr ptr_;
    //...
};
class Containing::NestedInterface {
};

请注意,一般来说,在 C++ 中,嵌套的 classes 不能像在其他语言中那样随心所欲地使用——您通常可以使用外部 [=23] 实现相同的效果=] 是的,他们这样表现得更好。 (它们不需要外部 class 的定义。)只有在少数情况下它们才是绝对必要的。 (想到 std::allocator<T>::rebind<U>。)