在 C++ 模块中将可变数量的参数转发到 SpdLog

问题描述 投票:0回答:1

我是一名专业的 C# 开发人员,正在启动一个 C++ 副项目。我的第一步是使用 spdlog 进行记录和运行。由于这是一个新的现代项目,我正在使用模块。

我编写了一个 Meyers Singleton 类,旨在封装 spdlog 并将其完全隐藏在模块中,以便在将来的任何时候我都可以换出不同的日志库,并且不需要更改客户端代码。任何调用代码只需要导入我的“Logger”包装器模块并开始记录。

记录器是共享库(“核心”)的一部分,它使用 spdlog 构建为静态库。

我有基本的功能,但我需要实现将发送到包装器方法的可变数量的参数转发到相应的 spdlog 方法(trace()、info() 等)的能力。

客户端应该能够使用这样的代码:

import Logger;

int main()
{
    //This is a static method that calls my singleton wrapper.
    Logger::Info("{1} is a {0}", "test", "This");
}

在 spdlog 实例上调用

info()
成员函数时,此调用工作正常。例如:

//This works fine calling on spdlog directly.
directSpdlogInstance->info("{1} is a {0}", "test", "This");

但是如果我像上面那样尝试对我的单例包装器“Logger”进行静态调用,我会收到错误。我试图从包装器中调用的 spdlog 函数的签名是这样的:

template <typename... Args>
inline void info(format_string_t<Args...> fmt, Args &&...args);

以下是我尝试过的一些实现及其错误:

template<typename...Args>
void Logger::Info(Args&&... args)
{
    //GetInstance() retrieves a spdlog logger instance.
    GetInstance()->info(std::forward<Args>(args)...);
}

当我尝试此操作时,出现编译错误 C7595:

'fmt::v9::basic_format_string::basic_format_string':对立即函数的调用不是 常量表达式 Nano C:\Dev\Nano\Projects\Core\src\Logger.cppm 30

好的。所以看来我不能简单地转发论点。 spdlog 似乎也在使用

fmt
库。所以我找到了 spdlog“SPDLOG_USE_STD_FORMAT”的预处理器#define,它似乎将其切换为使用 std 库版本的格式。

有了这个定义,我尝试像这样实现它:

template<typename...Args>
void Logger::Info(std::format_string<Args...> fmt, Args&&... args)
{
    GetInstance()->info(fmt, std::make_format_args(args...));
}

我收到编译器错误 C2664:

'void spdlog::logger::info>(std::basic_format_string>,std::_Format_arg_store<_Context,const char (&)[32]> &&)': 无法将参数 1 转换为 'std::basic_format_string' 到 'std::basic_format_string>' 和 [ _Context=std::format_context ] Nano C:\Dev\Nano\Projects\Core\src\Logger.cppm 34

编辑:我想我现在已经更进一步了。如果我实现这样的功能:

template<typename...Args>
void Logger::Info(std::format_string<Args...> fmt, Args&&... args)
{
    GetInstance()->info(fmt, std::forward<Args>(args)...);
}

然后项目编译成功:0 个错误,0 个警告!

但是现在我在使用记录器的控制台应用程序项目中遇到错误。这是链接器错误 LNK1104:

无法打开文件“C:\Dev\Nano in\windows-Debug\Core\Core.lib”

我的dll文件正在构建,但是现在没有相应的lib文件!我知道如果没有从 dll 导出任何内容,通常会发生这种情况。但显然我的模块代码正在导出公共静态方法:

export class Logger
{
public:
    Logger(const Logger& other) = delete;

    template<typename...Args>
    NN_API static void Info(std::format_string<Args...> fmt, Args&&... args);
...

并且 main() 函数正在如上所述调用它。 NN_API 是一个非常标准的 __declspec(dllexport) 定义。

我觉得我已经很接近了,但无法冲过终点线。有人可以帮忙吗?

如果有帮助,我已经设置了一个存储库,您可以在其中克隆我的简单项目(没有我最新的 info() 包装器实现)并查看:

GitHub 存储库

构建说明位于 GitHub 页面的自述文件中。应该很简单!预先感谢您,这消耗了我很多时间并阻碍了我前进!

c++ module variadic-templates spdlog
1个回答
0
投票

好的,所以通过我上面的尝试迭代,我最终达到了正确编译的语法,上面的@Jarod42指出了为什么该函数没有导出。回想起来很明显!

可变参数函数对 DLL 的使用者不可见的原因是它没有被生成。由于这是一个在运行时与消费应用程序链接的共享库(DLL),因此编译器无法知道要实例化哪个版本的可变参数函数!

因此,为了解决最后一个问题,我相信记录器需要变成静态库,以便可以在编译时确定可变参数函数的所有实例化。

© www.soinside.com 2019 - 2024. All rights reserved.