Форвардное объявление вне класса работает, но не когда вложено - PullRequest
0 голосов
/ 10 июня 2018

Предположим, у меня есть два класса A и B, использующие идиому pimpl.A предоставляет публичный API, содержащий указатель на B.Я получаю ошибку компиляции при объявлении вперед B в пределах A, но не при объявлении его снаружи.

Почему последний не будет работать?В обоих случаях я включаю b.hpp в a.cpp перед вызовом любых методов B.

Прямое объявление вне класса A

Этот пример работает нормально.

Файл 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

Файл a.cpp:

#include "b.hpp"
#include "a.hpp"

A::A() : b_( std::make_unique< B >() ) { }
A::~A() { }

void
A::Hi() {
        this->b_->Hi();
}

Файл b.hpp:

#ifndef _B_
#define _B_

class B {
public:
        void Hi();
};

#endif

Файл b.cpp:

#include "b.hpp"

#include <iostream>

void
B::Hi() {
        std::cout << "Hello World!" << std::endl;
}

Файл драйвера hello.cpp:

#include "a.hpp"

int main() {
        A a;
        a.Hi();
        return 0;
}

Компиляция: g++ hello.cpp a.cpp b.cpp -std=c++14

Предварительное объявление внутри класса A

Вот яперемещение вперед декларации B в A.

Файл 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

Я получаю следующие ошибки компиляции:

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,

1 Ответ

0 голосов
/ 10 июня 2018

Это потому, что вы не объявляете то же самое class B.B во втором примере объявлен как вложенный класс .Он имеет область действия A:: (поскольку в действительности он называется class A::B).Но затем вы пытаетесь использовать его как ::B (как в глобальной области видимости).

Это совершенно очевидно из сообщения об ошибке:

error: недопустимое использование неполного типа ' класс A :: B '

Это не может работать.Объявление вперед class B, внешнее по отношению к A, является правильным способом реализации этого.

...