在库中隐藏模板函数声明 [英] hide template function declaration in library

查看:140
本文介绍了在库中隐藏模板函数声明的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

首先,是大局.我有一个Logger课.我为该类创建了一个简化的接口,并为该接口创建了一个库.我想使用pimpl隐藏Logger类的实现,因此用户不需要Logger的标头.我在使用模板功能时遇到了麻烦...

First, the big picture. I have a Logger class. I've created a simplified interface for the class, and created a library for the interface. I'd like to use pimpl to hide the Logger class implementation, so the user doesn't need the Logger's headers. I'm having a bad time with template functions...

Logger标头的定义如下

The Logger header is defined like this

/* 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());
}


第一版

我已经创建了这样的界面


FIRST VERSION

I've created the interface like this

/* 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示例

I've generated the library, and here is a sample of a main.cpp that uses it

/* main.cpp */

#include <LoggerInterface.h>

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

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

Everything works, BUT the main includes LoggerInterface.h, so implicitly includes Logger.h. I'd like to get rid of Logger.h on the user code side.

我尝试使用pimpl习惯用法,但是模板功能让我头疼.我已经阅读了一些文档并进行了许多测试,但到目前为止还没有运气.这是几乎有"版本的代码.

I tried to use the pimpl idiom, but the template function is giving me headaches. I've read several docs and done many tests, but no luck so far. Here is the code of the "almost-there" version.

/* 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()函数出现无法解析的外部符号错误.

The main includes LoggerInterface.h, but doesn't need Logger.h due to the pimpl. Compiles ok, but awfully I get an unresolved external symbol error for the template log() function.

关于如何消除错误的任何想法?我的方法是一种好方法,还是遵循另一种实现目标的方法(创建一个没有Logger基类头的用户可以使用的库接口)更好呢?

Any idea about how to get rid of the error? Is my approach a good one, or is it better to follow a different implementation to achieve my goal (create a library interface that the user can use without the base Logger class headers)?

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

IMPORTANT NOTE: I can't edit the Logger class.

推荐答案

简单的答案是-您不能.问题在于,接口方法被实例化为具有每个不同参数集的不同函数",并且每次都会创建Logger函数模板的不同实例化.为此,它需要使Logger方法的整个定义都可访问,以便能够生成新的实例.

Simple answer is - you can't. The problem is that the interface method is instantiated as a "different function" with every different set of parameters, and in turn creates a different instantiation of the Logger function template each time. In order to do that, it needs to have the entire definition of the Logger method accessible to be able to generate the new instantiation.

如果隐藏它,则确实会为所有缺少的实例获取未解决的外部对象,因为在构建LoggerInterface.cpp时不会创建它们(因为当时尚不知道需要所有实例).

If you hide it, you will indeed get the unresolved externals for all the missing instantiations, because they are not created when the LoggerInterface.cpp is build (as it is not known at that time which all instantiations will be needed).

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

If there would be only some limited set of possible instantiations, you could explicitly instantiate all the needed versions and they could be exported from a library/used via PIMPL. However as this is not the case here (the types and count of arguments to the log() method can be quite arbitrary), this solution would not be practical in this case.

这篇关于在库中隐藏模板函数声明的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆