Резюме
Я пишу библиотеку и клиентское приложение.В библиотеке я пытаюсь написать оболочку вокруг другой статически связанной сторонней библиотеки (в частности, spdlog ) и пытаюсь использовать идиому pImpl, чтобы полностью скрыть ее от клиентского приложения.Проблема заключается в том, что сторонняя библиотека использует функции шаблонов с переменными значениями, и поэтому мне тоже нужно в моей библиотеке.
Фон
Моя первая попытка использования обертки была довольно тонкой и простой,но затем я получаю ошибки «Нет такого файла или каталога» в моем клиентском приложении, потому что сторонний заголовок включается в заголовок моей библиотеки.
Затем я попытался создать класс pImpl и получил его для компиляции., но снова в клиенте я получаю ошибки компоновщика «неопределенная ссылка».
Загрузка исходного кода для реализации в заголовок для моей обертки возвращает меня к первоначальной проблеме «Нет такого файла».Изучив это, я начинаю думать, что создание обертки вокруг шаблонов с переменными параметрами невозможно, но я не уверен.Это первый раз, когда я пытался создать переменную функцию / шаблон.
Пример кода
Вот как выглядит мой проект:
Почти все пространства имен, функцияимена, заголовки и т. д. были отредактированы (или удалены) для краткости и ясности.
Клиентское приложение - sandbox.cpp
#include "sandbox.h"
#include <logger.h> // <-- This is all I want clients to see.
int Sandbox::run() {
LOG_INFO("Hello World!"); // My library is providing this.
LOG_INFO("Hello {}", "indeed!"); // And, this variable input function.
return 0;
}
Моя библиотека - logger.h
class LoggerImp; // Forward declaration of implementation.
class LIB_EXPORT Logger {
public:
/* Constructors, destructor, etc. */
template <typename... Args>
void info(const char * fmt, Args &... args);
void info(const char * msg) { this->info("{}", msg); }
/* Other logging functions: trace, error, etc. */
private:
LoggerImp * _imp;
};
static Logger coreLogger("Core");
static Logger clientLogger("App");
#define LOG_INFO(args...) clientLogger.info(args)
/* Other such convenience definitions. */
Моя библиотека - logger.cpp
#include "logger.h"
#include "loggerimp.h"
Logger::Logger(std::string name) { _imp = new LoggerImp(name, this); }
Logger::~Logger() { delete _imp; }
template <typename... Args>
void Logger::info(const char * fmt, Args &... args) {
_imp->info(fmt, args...);
}
Моя библиотека - loggerimp.h
#include "logger.h"
#include <spdlog/spdlog.h>
#include <spdlog/sinks/stdout_color_sinks.h>
class LoggerImp {
public:
explicit LoggerImp(string name, Logger * pubInterface) :
_pubInterface(pubInterface) { // Back pointer.
_sink = make_shared<spdlog::sinks::stdout_color_sink_mt>();
_logger = make_shared<spdlog::logger>(name, _sink);
spdlog::initialize_logger(_logger);
// The above three lines create the actual logging object
// that my library is wrapping and hiding from its clients.
}
template <typename... Args>
inline void info(const char * fmt, const Args &... args) {
_logger->info(fmt, args...); // Third-party logging function.
}
}
Ожидаемые результаты
Как уже упоминалось выше, я просто хочу клиентовмоей библиотеки, чтобы иметь возможность включать заголовки, такие как <logger.h>
, и не нужно настраивать свои проекты, чтобы также находить и обрабатывать все зависимости моей библиотеки, но, поскольку в настоящее время я использую сторонний инструмент, который использует шаблоны с переменными числами, я 'я не вижу способа, которым я могу скрыть это от моих клиентов, учитывая, хм ... "не настоящую функцию" природы шаблонов.