基类子句前的类声明是否属于合法的C++前向声明?
继承自包含自身的模板类的写法是否合法?
在一个主题无关的C++视频中,我看到如下定义:
#include <vector> // before ":" V is forward declared, it's enough for std::vector? // node in a tree struct V : std::vector<V> {};
(注释为我自行添加)
我的理解是这种看似循环的声明是可行的,因为在base-clause位置,struct V已被(前向)声明。但这是否属于合法的C++语法?我在class declaration文档中未找到明确说明。
forward declaration的定义是单独的(如struct V;,之后可声明std::vector<V>),但未提及完整类声明语法中的情况。
derived class文档中的表述:
任何类类型(无论使用class还是struct关键字声明)都可以被声明为派生类...
(粗体为我所加)似乎暗示class/struct关键字(不带结尾;)已是完整声明。这是否属实?C++标准中有更明确的说明吗?
若合法,这将为我带来有趣的设计可能,因此我希望确认其合法性。
补充示例
一个更明确的无std::vector示例:
template <typename T> struct refwrapper { T* wrapped; virtual ~refwrapper() = default; }; template <typename T> struct plainwrapper { T wrapped; virtual ~plainwrapper() = default; }; // OK? R is declared at the base-clause struct R : refwrapper<R> {}; // KO P is incomplete at the base-clause // struct P: plainwrapper<P> // {};
解答
这种写法是合法的,核心原因如下:
- 类名的声明时机:当编写
struct V : ...时,在冒号之前,V已经被引入当前作用域,成为不完全类型(已声明但未定义),直到整个类定义结束后才会成为完全类型。在base-clause中引用V时,它的身份就是不完全类型。 - 模板对不完全类型的支持:
std::vector<T>从C++17开始被标准明确允许接受不完全类型作为模板参数(很多编译器在更早版本就已支持),因为vector的内部实现只需要T的声明来管理指针、引用等,不需要T的完整定义。- 示例中的
refwrapper<R>合法,是因为它仅持有R*指针,而指针类型的声明只需要R的前向声明(不完全类型)即可;而plainwrapper<P>非法,是因为它直接持有P的实例,这要求P是完全类型,但此时P还未完成定义。
C++标准的明确依据在[class.name]章节中:类名在类定义的class-key(struct/class)之后立即被声明,成为不完全类型,在类定义的结束处(即}之后)才完成定义,成为完全类型。因此在base-clause中使用该类名时,只要基类模板接受不完全类型作为参数,整个写法就是合法的。
内容的提问来源于stack exchange,提问作者Oersted
相关产品推荐
相关产品推荐

