c++ - 在库中隐藏模板函数声明

标签 c++ pimpl-idiom template-function

首先,大局观。我有一个记录器类。我为该类创建了一个简化的接口(interface),并为该接口(interface)创建了一个库。我想使用 pimpl 来隐藏 Logger 类的实现,因此用户不需要 Logger 的 header 。我在使用模板函数时遇到了麻烦...

Logger header 是这样定义的

/* Logger.h */

class Logger
{
  public:
    virtual ~Logger(){};
  public:
    template <typename... Args> void log(const char* fmt, const Args&... args)
    {
      printf(fmt, &args...);
    }
};

std::shared_ptr<Logger> create_logger()
{
  return std::shared_ptr<Logger>(new Logger());
}

第一版

我创建了这样的界面

/* LoggerInterface.h */

#include "Logger.h"

class LoggerInterface
{
  public:
    LoggerInterface();
  public:
    template <typename... Args> void log(const char* fmt, Args&&... args)
    {
      logger->log(fmt, std::forward<Args>(args)...);
    }
  private:
    std::shared_ptr<Logger> logger;
};

/* LoggerInterface.cpp */

#include "LoggerInterface.h"

LoggerInterface::LoggerInterface()
{
  logger = create_logger();
}

我已经生成了库,这里是使用它的 main.cpp 示例

/* main.cpp */

#include <LoggerInterface.h>

int main()
{
  LoggerInterface loggerIntreface;
  loggerIntreface.log("Welcome %s\n", "logger");
  return 0;
}

一切正常,但主要包含 LoggerInterface.h,因此隐式包含 Logger.h。我想在用户代码端摆脱 Logger.h


隐藏记录器尝试

我尝试使用 pimpl 习惯用法,但模板函数让我很头疼。我已经阅读了几篇文档并做了很多测试,但到目前为止还没有运气。这是“几乎就在那里”版本的代码。

/* LoggerInterface.h */

class LoggerInterface
{
  private:
    class LoggerImpl;
  public:
    LoggerInterface();
  public:
    template <typename... Args> void log(const char* fmt, Args&&... args);
  private:
    std::shared_ptr<LoggerImpl> logger;
};

/* LoggerInterfacePrivate.h */

#include "Logger.h"
#include "LoggerInterface.h"

class LoggerImpl : public Logger
{}

template <typename... Args> inline void LoggerInterface::log(const char* fmt, Args&&... args)
{
  logger->log(fmt, std::forward<Args>(args)...);
}

/* LoggerInterface.cpp */

#include "LoggerInterfacePrivate.h>

LoggerInterface::LoggerInterface()
{
  logger = std::dynamic_pointer_cast<Logger>(create_logger());
}

主要方面没有新内容

/* main.cpp */

#include <LoggerInterface.h>

int main()
{
  LoggerInterface loggerIntreface;
  loggerIntreface.log("Welcome %s\n", "logger");
  return 0;
}

主要包括LoggerInterface.h,但由于pimpl,不需要Logger.h。编译正常,但可怕的是我得到了模板 log() 函数的未解析的外部符号错误。

知道如何消除错误吗?我的方法是好的,还是遵循不同的实现来实现我的目标(创建一个用户可以在没有基本 Logger 类 header 的情况下使用的库接口(interface))更好?

重要说明:我无法编辑 Logger 类。

最佳答案

简单的答案是 - 你不能。问题在于接口(interface)方法被实例化为具有每组不同参数的“不同函数”,并且每次都会创建 Logger 函数模板的不同实例化。为此,它需要能够访问 Logger 方法的整个定义,以便能够生成新实例。

如果你隐藏它,你确实会得到所有缺失实例化的未解析外部,因为它们不是在构建 LoggerInterface.cpp 时创建的(因为当时不知道哪些实例化将需要)。

如果只有一些有限的可能实例化集,您可以显式实例化所有需要的版本,并且它们可以从库中导出/通过 PIMPL 使用。然而,由于这里的情况并非如此(log() 方法的参数类型和数量可能是任意的),因此该解决方案在这种情况下不切实际。

关于c++ - 在库中隐藏模板函数声明,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45239107/

相关文章:

c++ - C++中链表的长度

c++ - 对 std/boost 移动的模糊调用

c++ - C++中输入名字和转载的堆栈程序

c++ - Pimpl、私有(private)类前向声明​​、范围解析运算符

c++ - pimpl 助手与继承不明确

c++ - 粉刺 : Avoiding pointer to pointer with pimpl

带有从迭代器获取的指针参数的 C++ 模板函数给出错误

c++ - 部分特化可变参数模板类的方法

c++ - 未实例化模板函数的处理