【问题标题】:Is there a syntax for incomplete nested type without a forward declaration?没有前向声明的不完整嵌套类型是否有语法?
【发布时间】:2015-09-03 05:17:43
【问题描述】:

以下程序会产生诊断错误。

#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&lt;&gt; 时被假定为没有嵌套。如果是这样,是否有一种语法可以让shared_ptr&lt;&gt; 知道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_; }
        //...
    };
    //...

【问题讨论】:

  • 一种替代方法是将 typedef 行移动到“class Nested {}”块的末尾...当然,您将无法再在该块中使用 typedef ,因此您需要在方法参数中明确指定基础类型(“std::shared_ptr”)。
  • 如果您只打算在Nested 的范围内使用Ptr,我相信您也可以将typedef in 放在Nested 定义中。当然是compiles.
  • 生成激发问题的示例不会再使示例最小化。所有问题都必须充分激发吗?
  • 那么为什么不公开NestedPtr typedef,如果你在Nested 类中 typedef 它呢?我假设您想使用 Ptr 是有原因的,而不是表明 Ptr 指向 to? 的东西
  • 除非使用class-key identifier;语法,在elaborated-type-specifier中首先声明的类总是introduced in a namespace or block scope , 而不是类作用域。

标签: c++ c++11 nested forward-declaration


【解决方案1】:

没有。

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

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

有时类中的交叉依赖项可能会使这很难做到。在这种情况下,您需要做的就是避免内联定义引用类,而是将 other 类声明为外联,如下所示:

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

请注意,一般来说,在 C++ 中,嵌套类不能像在其他语言中那样随意使用——通常可以使用外部类来实现相同的效果,而且它们的表现要好得多。 (它们不需要外部类的定义。)只有在少数情况下它们是绝对必要的。 (想到了std::allocator&lt;T&gt;::rebind&lt;U&gt;。)

【讨论】:

  • 不过,它仍然有一个前向声明。 (第 2 行)
  • @donjuedo:因此 "No""workaround" ,如果你真的阅读了第一行。
  • 是的,我确实阅读了第一行。我缺少的是重新组织声明其余部分的动机,因为它不会改变“无法解决”部分。你说他需要,但你没有说为什么。
  • @donjuedo:这是一个非常不同的问题。是的,你是对的,这里没有必要;我会改变答案来解决这个问题。不过,有时成员之间有交叉引用,因此这种方法很有用,所以我对其进行了说明。
【解决方案2】:

您应该将声明 class Nested; 保留在其中。

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

编译器需要知道标记Nested 是一个类,而不是别的东西。在编译器到达Ptr 时,该信息就足够了,并且类的详细信息尚不相关。然后编译器到达完整的Nested 声明,详细信息可用于该类的所有未来使用。

【讨论】:

  • class Nested 前向声明使编译器清楚地知道 Nested 是嵌套的。注意class Nestedshared_ptr&lt;&gt; 中的使用。
  • 我猜你的意思是模板类型区域中的关键字class 应该足够了,因此之前的前向声明将是多余的。逻辑。
猜你喜欢
  • 1970-01-01
  • 2016-11-06
  • 1970-01-01
  • 2013-11-04
  • 2013-07-09
  • 2010-10-31
相关资源
最近更新 更多