C4150: удаление указателя на неполный тип и идиома PIMPL

0

есть ли способ правильно реализовать идиому PIMPL с классом шаблона в C++?

Например, у меня есть следующий класс PIMPL:

template <typename T> struct PrivateImplementation {
    PrivateImplementation<T>(T* impl) : implementation(impl) {

    }
    ~PrivateImplementation<T>() {
        if (implementation != nullptr) delete implementation;
    }
    PrivateImplementation<T>(const PrivateImplementation<T>& c) = delete;
    void operator=(const PrivateImplementation<T>& a) = delete;
    PrivateImplementation<T>(PrivateImplementation<T>&& m) { 
        implementation = m.implementation;
        m.implementation = nullptr;
    }

    T* operator->() const {
        return implementation;
    }

    private:
    T* implementation;
};

Однако, когда я использую его, как показано ниже, компилятор жалуется (предупреждение), что я удаляю неполный тип:

logger.h

class LoggerStream {
    public:
    LoggerStream(std::wstring componentName);
    ~LoggerStream();
    LoggerStream(const LoggerStream&) = delete;
    void operator=(const LoggerStream&) = delete;
    LoggerStream(LoggerStream&&);

    void Write(std::wstring message, const char* __function__, const char* __file__, int __line__) const;
    void Write(std::wstring message) const;

    private:
    struct LoggerStreamImpl;
    PrivateImplementation<LoggerStreamImpl> impl;
};

Logger.cpp

struct LoggerStream::LoggerStreamImpl {
    LoggerStreamImpl(std::wstring componentName) : componentName(componentName) { }
    ~LoggerStreamImpl() = default;
    LoggerStreamImpl(const LoggerStreamImpl&) = delete;
    void operator=(const LoggerStreamImpl&) = delete;
    LoggerStreamImpl(LoggerStreamImpl&&);

    const std::wstring componentName;
};

LoggerStream::LoggerStream(std::wstring componentName)
    : impl(new LoggerStreamImpl { componentName }) { }

LoggerStream::~LoggerStream() { }

void LoggerStream::Write(std::wstring message, const char* __function__, const char* __file__, int __line__) const {
    // Some implementation
}

void LoggerStream::Write(std::wstring message) const {
    // Some implementation
}

У меня явно есть определенный деструктор для LoggerStreamImpl прямо там.cpp, так что даёт?

Спасибо.

Теги:
pimpl-idiom

2 ответа

0

Любой файл, который включает logger.h, пытается скомпилировать шаблон для себя. Итак, скажем, у вас есть файл main.cpp который содержит вашу int main() (или другую точку входа), и этот файл включает logger.h. Main.cpp увидит logger.h, попытается разобрать его, и во время процесса синтаксического анализа попытается скомпилировать версию шаблона PrivateImplementation для T = LoggerStreamImpl. Вы можете уйти от этого, если ваш компилятор совместим с С++ 11 и позволяет вам сказать, что PrivateImplementation определяется извне.

  • 0
    Я использую компилятор C ++ 11 (но соответствие не совсем его сильная сторона) ... Как бы я сказал ему, что «PrivateImplementation определяется внешне»?
  • 0
    Линия extern template class PrivateImplementation<LoggerStreamImpl>; в logger.h непосредственно перед определением класса следует сообщить компилятору, что этот класс создан в другом месте и не создавать его. Я считаю, что вам нужно будет включить template class PrivateImplementation<LoggerStreamImpl>; линии template class PrivateImplementation<LoggerStreamImpl>; в logger.cpp, чтобы заставить этот файл на самом деле создать экземпляр шаблона, иначе он нигде не будет создан. Дайте мне знать, если это работает, поскольку я еще не играл с внешними шаблонами.
Показать ещё 5 комментариев
0

Когда я храню std :: unique_ptr с типом i, я не хочу полностью видимого, например pimpl, я использую настраиваемый делектор, где оператор() определен в cpp с полным видимым классом.

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

Ещё вопросы

Сообщество Overcoder
Наверх
Меню