Шаблонные классы с неверной идиомой

Как описано в библиотеке MSDN Вот Я хотел немного поэкспериментировать с идиомой прыщей. Прямо сейчас у меня есть Foo.hpp с

template<typename T>
class Foo {
public:
typedef std::shared_ptr<Foo<T>> Ptr;

Foo();
private:
class Impl;
std::unique_ptr<Impl> pImpl;
};

где T параметр не используется еще. Реализация хранится в Foo.cpp

template<typename T>
class Foo<T>::Impl {
public:
int m_TestVar;
};

template<typename T>
Foo<T>::Foo() : pImpl(new Impl) {
this->pImpl->m_TestVar = 0x3713;
}

В настоящее время у компилятора есть две ошибки и одно предупреждение:

  • use of undefined type 'Foo<T>::Impl'; ... vc\include\memory in line 1150
  • can't delete an incomplete type; ... vc\include\memory in line 1151
  • deletion of pointer to incomplete type 'Foo<T>::Impl'; no destructor called; ... vc\include\memory in line 1152

Что такое конфликт и как я могу его решить?

Редактировать. Удален звонок в std::make_shared — копия&Ошибка вставки на основе одной старой версии.

1

Решение

У меня была похожая проблема — у нас есть базовый класс в нашей системе NamedComponent и я хотел создать шаблон, который берет существующий именованный компонент и преобразует его в фасад pimpl.

То, что я сделал, разделило шаблон на заголовок и встроенный файл, и создал функцию, которая будет вызывать создание экземпляра шаблона. Это позволяет реализации находиться в библиотеке с экземплярами шаблона фасада с этой реализацией, и клиент может использовать фасад на основе шаблона и предварительного объявления реализации.

заголовок ‘Foo.h’:

template<class T> class Foo
{
public:
Foo ();
virtual ~Foo();

private:
T *impl_;

public:
// forwarding functions
void DoIt();
};

встроенные функции ‘Foo.inl’:

#include "Foo.h"
template<class T> Foo<T>::Foo() :
impl_ ( new T )
{
}

template<class T> Foo<T>::~Foo()
{
delete impl_;
}

// forwarding functions
template<class T> void Foo<T>::DoIt()
{
impl_ -> DoIt();
}

// force instantiation
template<typename T>
void InstantiateFoo()
{
Foo<T> foo;
foo.DoIt();
}

Файл реализации cpp — включает шаблон встроенных функций, определяет реализацию, ссылается на функцию создания экземпляра:

#include "Foo.inl"
class ParticularImpl {
public:
void DoIt() {
std::cout << __FUNCTION__ << std::endl;
}
};

void InstantiateParticularFoo() {
InstantiateFoo<ParticularImpl>();
}

файл клиента cpp — включает заголовок шаблона, объявляет реализацию и использует фасад pimpl:

#include "Foo.h"class ParticularImpl;

int main () {
Foo<ParticularImpl> bar;

bar.DoIt();
}

Возможно, вам придется поиграться с содержимым функции InstantiateFoo, чтобы заставить компилятор создавать экземпляры всех функций — в моем случае, база вызвала все функции pimpl в шаблонных методах, поэтому, как только на них ссылались, все они были. Вам не нужно вызывать функции Instantiate, просто ссылку на них.

2

Другие решения

IMHO PIMPL не имеет большого смысла с шаблонами, если вы не знаете все возможные параметры шаблона и этот набор довольно мал. Проблема в том, что вы будете иметь Impl Реализация в заголовочном файле в противном случае, как было отмечено в комментариях. Если количество возможных T параметры малы, вы все равно можете пойти с разделением, но вам нужно объявить специализации в заголовке, а затем явно создать их экземпляр в исходном файле.

Теперь к ошибке компилятора: unique_ptr<Impl> требует определения Impl быть доступным. Вам нужно будет напрямую использовать new а также delete в ктор Foo::Foo и дтор Foo::~Fooсоответственно вместо этого и отбросьте удобство / безопасность умных указателей.

1

По вопросам рекламы [email protected]