'Which STL data structures with an incomplete type stored can be used as a class member?
As far as I know, since C++17 some STL data structures may "exist" with an incomplete type as the template parameter which describes the type stored. For example, I may use std::unique_ptr<Incomplete>
(I'm not sure if it's a data structure though) or std::vector<Incomplete>
as class members if all properties of the class (which need Incomplete
's definition) are implemented in a separate .cpp file:
class Incomplete;
using Complete = int;
class Foo {
private:
std::unique_ptr<Incomplete> u_p;
std::vector<Incomplete> v;
std::deque<Incomplete> d;
std::list<Incomplete> l;
std::set<Incomplete> s;
std::unordered_map<Complete, Complete> u_m_cc;
std::unordered_map<Complete, Incomplete> u_m_ci;
std::unordered_map<Incomplete, Complete> u_m_ic;
std::unordered_map<Incomplete, Incomplete> u_m_ii;
public:
// implemented in a separate .cpp which has Incomplete defined:
Foo();
Foo(Foo&&);
Foo& operator=(Foo&&);
Foo(Foo const&);
Foo& operator=(Foo const&);
~Foo();
};
So, which of the data members listed above are valid for such usage? What about other data structures, smart pointers etc.?
Solution 1:[1]
Assuming none of the classes members are used explicitly or implicitly until the type is complete:
The template argument can always be incomplete for std::unique_ptr
and std::shared_ptr
since C++11, see [unique.ptr]/5 and [util.smartptr.shared]/2 respectively.
Support of incomplete types in containers was added with N4510 to C++17, but only for
std::vector
std::list
std::forward_list
and only if the allocator used fulfills the allocator completeness requirements, namely that, even if the value type itself is not complete, the allocator type X
itself is a complete type and so are all members of std::allocator_traits<X>
, except ::value_type
. The default allocator std::allocator
fulfills these requirements.
None of the other containers can be used with incomplete types. According to the proposal linked above the scope was limited to these three containers "as a first step" because the major implementations already had support for it.
Solution 2:[2]
since C++17 some STL data structures may "exist" with an incomplete type as the template parameter which describes the type stored.
This is incorrect.
Since C++17, some STL types may be declared with an incomplete type as the template parameter.
By the time the types are instantiated, the types must be complete.
For example: (untested code)
struct T; // incomplete
using TV = std::vector<T>; // declared a type using incomplete type T; fine.
TV tv0; // attempt to declare a variable of type TV; fails to compile.
struct T { int v; }; // T is now complete
TV tv1; // compiles
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 | Marshall Clow |