Я использую идиому PIMPL, и, в частности, я использую шаблон, предоставленный от this post. Учитывая множество классов ниже и компиляцию с VS2015 Update 3, я получаю ошибку компиляции:Почему этот тип является неполным при использовании идиомы PIMPL?
Ошибки C2027 использование неопределенного типа «C :: C_impl» (компиляции исходного файл \ SRC a.cpp)
Ошибка C2338 не может удалить неполный типа (компиляции исходного файла Src \ a.cpp)
предупреждения C4150 удаление указателя на незавершенный тип «C :: C_impl»; нет деструктора называется (компиляции исходного файла ЦСИ \ a.cpp)
Я не могу решить эту проблему раскомментировав C::~C()
, что приводит меня к мысли, что что-то мешает ~C()
от автоматического порождена, но я чего не понимаю. Согласно this reference, деструктор для типа T неявно определяется как удаляется, если какой-либо из следующих условий:
(оператор удаления()
- Т имеет не статический элемент данных, который не может быть разрушенное производственное (был удален или недоступен деструктор)
- T имеет прямой или виртуальный базовый класс, который не может быть разрушен (удалены или недоступны деструкторы)
- T является объединением и имеет вариантный элемент с нетривиальным деструктором.
- неявно объявленная деструктор виртуальная (так как базовый класс имеет виртуальный деструктор) и поиск для функции Deallocation приводит к вызову неоднозначной, удалять или недоступную функцию.
Предметы # 2, 3 и 4, очевидно, не применяются к C
, и я не считаю, что # 1 применяется потому, что pimpl<>
(C
«s только члены) определяет деструктор явно.
Может кто-то пожалуйста, объясните что происходит?
хиджры
#pragma once
#include <Pimpl.h>
class A
{
private:
struct A_impl;
pimpl<A_impl> m_pimpl;
};
B.h
#pragma once
#include "C.h"
class B
{
private:
C m_C;
};
C.h
#pragma once
#include <Pimpl.h>
class C
{
public:
// Needed for the PIMPL pattern
//~C();
private:
struct C_impl;
pimpl<C_impl> m_pimpl;
};
a.cpp
#include <memory>
#include "A.h"
#include "B.h"
#include <PimplImpl.h>
struct A::A_impl
{
std::unique_ptr<B> m_pB;
};
// Ensure all the code for the template is compiled
template class pimpl<A::A_impl>;
C.cpp
#include <C.h>
#include <PimplImpl.h>
struct C::C_impl { };
// Needed for the PIMPL pattern
//C::~C() = default;
// Ensure all the code for the template is compiled
template class pimpl<C::C_impl>;
Для полноты реализации Pimpl с поста ссылки выше:
pimpl.h
#pragma once
#include <memory>
template<typename T>
class pimpl
{
private:
std::unique_ptr<T> m;
public:
pimpl();
template<typename ...Args> pimpl(Args&& ...);
~pimpl();
T* operator->();
T& operator*();
};
PimplImpl.ч
#pragma once
#include <utility>
template<typename T>
pimpl<T>::pimpl() : m{ new T{} } {}
template<typename T>
template<typename ...Args>
pimpl<T>::pimpl(Args&& ...args)
: m{ new T{ std::forward<Args>(args)... } }
{
}
template<typename T>
pimpl<T>::~pimpl() {}
template<typename T>
T* pimpl<T>::operator->() { return m.get(); }
template<typename T>
T& pimpl<T>::operator*() { return *m.get(); }
Несколько замечаний о коде выше:
- Я пытаюсь выставить
A
иC
потребителям моей библиотеки и сохранитьB
внутренний. - Здесь нет B.cpp, это было бы empy.
Это имеет смысл, я не знал, что он был создан в точке использования. Благодаря! –