I'm not sure if my question title is the most appropriate and I will change it happily to something clearer if I get adequate suggestion.
In a C++ video whose subject is not the one here, I saw this definition:
#include <vector>
// before ":" V is forward declared, it's enough for std::vector?
// node in a tree
struct V : std::vector<V> {};
(comments are my own).
My understanding is that it is possible to have this seemingly circular declaration, because at the base-clause location, struct V is already (forward) declared.
But is it legal C++ as I don't find that class declaration is explicit about this.
forward declaration is defined by itself (struct V;, then you can declare a std::vector<V>) but not in the full class declaration syntax.
The wording in derived class:
Any class type (whether declared with class-key class or struct) may be declared as derived...
(bold mine)
seems to imply that class-key class or class-key struct (without ending ;) are already full declarations. Is it true, is it more explicit in the standard?
If yes, it may give me opportunities for interesting designs, so I would like to be sure that it's legal.
[EDIT] a more explicit example, without 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>
// {};
The class name is visible to lookup immediately after the identifier. See [basic.scope.pdecl]/3.
However, as usual, until the closing
}of the class definition the class is incomplete. The base class specifier is not an exception as some so-called complete class contexts are.Using a type as base class requires it to be complete. Therefore
std::vector<V>will be instantiated by the use as base class specifier, whereVis still incomplete.Generally instantiating a standard library template with an incomplete type as template argument causes undefined behavior.
However, since C++17
std::vectoris one of the exceptions: It is permitted to instantiatestd::vectorwith an incomplete type as template argument as long as the type is completed before any member function of thestd::vectorspecialization is referenced.So yes,
struct V : std::vector<V> {};is valid since C++17 since it doesn't reference any member ofstd::vector<V>before the closing}.