Reputation: 792
Suppose I have two classes A
and B
employing the pimpl
idiom. A
provides the public API, holding a pointer to B
. I get a compilation error when forward-declaring B
within A
, but not when declaring it outside.
Why would the latter not work? In both cases I am including b.hpp
within a.cpp
before calling any methods of B
.
A
This example works normally.
File a.hpp
:
#ifndef _A_
#define _A_
#include <memory>
class B; // forward declaration, defined in a.cpp
class A {
public:
A();
~A();
void Hi();
private:
std::unique_ptr< B > b_;
};
#endif
File a.cpp
:
#include "b.hpp"
#include "a.hpp"
A::A() : b_( std::make_unique< B >() ) { }
A::~A() { }
void
A::Hi() {
this->b_->Hi();
}
File b.hpp
:
#ifndef _B_
#define _B_
class B {
public:
void Hi();
};
#endif
File b.cpp
:
#include "b.hpp"
#include <iostream>
void
B::Hi() {
std::cout << "Hello World!" << std::endl;
}
Driver file hello.cpp
:
#include "a.hpp"
int main() {
A a;
a.Hi();
return 0;
}
Compiling: g++ hello.cpp a.cpp b.cpp -std=c++14
A
Here I am moving the forward declaration of B
within A
.
File a.hpp
:
#ifndef _A_
#define _A_
#include <memory>
class A {
public:
A();
~A();
void Hi();
private:
class B; // forward declaration, defined in a.cpp
std::unique_ptr< B > b_;
};
#endif
I receive the following compilation errors:
a.cpp: In member function ‘void A::Hi()’:
a.cpp:9:10: error: invalid use of incomplete type ‘class A::B’
this->b_->Hi();
^
In file included from a.cpp:2:0:
a.hpp:12:8: error: forward declaration of ‘class A::B’
class B;
^
In file included from /usr/include/c++/4.9/memory:81:0,
from a.hpp:4,
from a.cpp:2:
/usr/include/c++/4.9/bits/unique_ptr.h: In instantiation of ‘typename std::_MakeUniq<_Tp>::__single_object std::make_unique(_Args&& ...) [with _Tp = A::B; _Args = {}; typename std::_MakeUniq<_Tp>::__single_object = std::unique_ptr<A::B>]’:
a.cpp:4:36: required from here
/usr/include/c++/4.9/bits/unique_ptr.h:765:69: error: invalid use of incomplete type ‘class A::B’
{ return unique_ptr<_Tp>(new _Tp(std::forward<_Args>(__args)...)); }
^
In file included from a.cpp:2:0:
a.hpp:12:8: error: forward declaration of ‘class A::B’
class B;
^
In file included from /usr/include/c++/4.9/memory:81:0,
from a.hpp:4,
from a.cpp:2:
/usr/include/c++/4.9/bits/unique_ptr.h: In instantiation of ‘void std::default_delete<_Tp>::operator()(_Tp*) const [with _Tp = A::B]’:
/usr/include/c++/4.9/bits/unique_ptr.h:236:16: required from ‘std::unique_ptr<_Tp, _Dp>::~unique_ptr() [with _Tp = A::B; _Dp = std::default_delete<A::B>]’
a.cpp:4:36: required from here
/usr/include/c++/4.9/bits/unique_ptr.h:74:22: error: invalid application of ‘sizeof’ to incomplete type ‘A::B’
static_assert(sizeof(_Tp)>0,
Upvotes: 1
Views: 390
Reputation: 33864
It is because you are not declaring the same class B
. B
in your second example is declared as a nested class. It has the scope A::
(as in it is actually named class A::B
). But then you try to use it as ::B
(as in global scope).
This is quite apparant from the error message:
error: invalid use of incomplete type ‘class A::B’
This cannot work. Forward declaring class B
external to A
is the correct way to implement this.
Upvotes: 3