This example shows strange behavior of compilers (msvc14, gcc, clang), but I did't find explanation.
When we implement pipml idiom and use forward declaration we need to consider that unique_ptr has own specific behavior with incomplete types. This cases was mentioned here and here.
But when we move definition of forwarded class to another header file and include headers in one place later with usage of client class, compilers become insane - in some special cases of destructor declaration they says about incomplete type.
Here is an minimal example. If uncomment "#define CASE_2" or "#define CASE_3" and try to build it, there will be compilation error.
file foo.h
#ifndef FOO_H
#define FOO_H
class Foo{};
#endif // FOO_H
file base.h
#ifndef BASE_H
#define BASE_H
#include <memory>
//#define CASE_1
//#define CASE_2
//#define CASE_3
class Foo;
class Base
{
public:
#if defined(CASE_1)
~Base() = default; // OK!
#elif defined(CASE_2)
~Base() {}; // error: invalid application of 'sizeof' to incomplete type 'Foo'
#elif defined(CASE_3)
~Base(); // error: invalid application of 'sizeof' to incomplete type 'Foo'
#endif
// OK!
private:
std::unique_ptr<Foo> m_foo;
};
#endif // BASE_H
file base.cpp
#include "base.h"
#if defined(CASE_3)
Base::~Base()
{
}
#endif
file main.cpp
#include "foo.h" // No matter order of this includes
#include "base.h" //
int main()
{
Base b;
}