I have read Is std::unique_ptr<T> required to know the full definition of T? and Forward declaration with unique_ptr?, but my question is more specific.
The following compiles:
// Compile with $ g++ -std=c++11 -c <filename>
#include <memory>
class A; // fwd declaration
class AUser
{
AUser(); // defined elsewhere
~AUser(); // defined elsewhere
std::unique_ptr<A> m_a;
};
The following doesn't:
// Compile with $ g++ -std=c++11 -c <filename>
#include <memory>
class A; // fwd declaration
class AUser
{
AUser(); // defined elsewhere
~AUser(); // defined elsewhere
std::unique_ptr<A> m_a{nullptr};
};
The error
$ g++ -std=c++11 -c fwd_decl_u_ptr.cpp
In file included from /usr/include/c++/4.7/memory:86:0,
from fwd_decl_u_ptr.cpp:3:
/usr/include/c++/4.7/bits/unique_ptr.h: In instantiation of ‘void std::default_delete<_Tp>::operator()(_Tp*) const [with _Tp = A]’:
/usr/include/c++/4.7/bits/unique_ptr.h:173:4: required from ‘std::unique_ptr<_Tp, _Dp>::~unique_ptr() [with _Tp = A; _Dp = std::default_delete<A>]’
fwd_decl_u_ptr.cpp:9:33: required from here
/usr/include/c++/4.7/bits/unique_ptr.h:63:14: error: invalid application of ‘sizeof’ to incomplete type ‘A’
EDIT:
As far as I understand, what is happening here is that the in-class initializer implies being capable of initializing unique_ptr<A>
already at the moment of declaration of AUser
. Since the type unique_ptr<A>
is actually unique_ptr<A, default_delete<A>>
, being able to initialize it implies being able to initialize default_delete<A>
. And, for that, A
has to be fully defined.
The weak link in this reasoning is the assumption that the in-class initializer implies capability of initializing the respective data member at the moment of declaration of the class! This seems an intuitive self-evidence, since the initializer is part of the declaration. But I would be more comfortable if I found something in the standard explicitly stating that. Otherwise I can still think of implementation solutions that wouldn't require it. For instance, the compiler could simply take the initializer expression and apply it only in constructors where the initialization of the attribute wasn't explicitly given.
So, can anyone refer me to a standard section/excerpt that implies the necessity for the full definition of A in the second case? I didn't find much about in-class initializers in the standard (only found them referred to as "brace-or-equal-initializers of non-static data members"), but nothing related to this.