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, where V
is still incomplete.
Generally instantiating a standard library template with an incomplete type as template argument causes undefined behavior.
However, since C++17 std::vector
is one of the exceptions: It is permitted to instantiate std::vector
with an incomplete type as template argument as long as the type is completed before any member function of the std::vector
specialization is referenced.
So yes, struct V : std::vector<V> {};
is valid since C++17 since it doesn't reference any member of std::vector<V>
before the closing }
.