首页 > 解决方案 > 传递可变参数

问题描述

下面是一个简单的记录器类,我实现了我的项目。

/* g++ test.cpp -o test */

#include <fstream>
#include <string>

#include "fmt/fmt.h"

typedef enum Severity
{
    LOG_INFO = 0,
    LOG_WARNING,
    LOG_ERROR
} Severity;

class Logger
{
public:
    Logger(const std::string &log_file);
    ~Logger();

    template <typename... Args> void DoLog(Severity severity, const std::string& context, fmt::format_string<Args...> fmt, Args&&...args);
private:
    std::ofstream fout;
};

static const std::string severity_str[3] = {
    "INFO",
    "WARNING",
    "ERROR"
};

Logger::Logger(const std::string &log_file)
{
    fout.open(log_file, std::ofstream::out | std::ofstream::trunc);
}

Logger::~Logger()
{
    fout.close();
}

template <typename... Args>
void Logger::DoLog(Severity severity, const std::string& context, fmt::format_string<Args...> fmt, Args&&...args)
{
    fout << fmt::format("[{:<7}] [{}] {}", severity_str[severity], context, fmt::format(fmt, std::forward<Args>(args)...)) << std::endl;
}

int main()
{
    Logger log("log.txt");
    log.DoLog(LOG_INFO, "0", "Yo");
    log.DoLog(LOG_INFO, "1", "Hello {}", 42);
    log.DoLog(LOG_ERROR, "2", "Word {0:02X}", 0xFF);
    log.DoLog(LOG_WARNING, "3", "! {} {}", 4, 5);
    uint8_t opcode = 0xDD;
    log.DoLog(LOG_ERROR, "CPU::HandlePrefixCB", "Unknown opcode: {0:02X}", opcode);
    uint8_t &ref = opcode;
    log.DoLog(LOG_ERROR, "CPU::HandlePrefixCB", "Unknown opcode: {0:02X}", ref);
    return 0;
}

即使这个文件编译和运行没有问题,当我将它们添加到我的项目代码库并编译时,g++ 会输出一堆未定义的引用,如下所示

C:/TDM-GCC-64/bin/../lib/gcc/x86_64-w64-mingw32/9.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: obj/CPUOpcodes.o:CPUOpcodes.cpp:(.text+0xf47): undefined reference to `void Logger::DoLog<unsigned char&>(Severity, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, fmt::v8::basic_format_string<char, fmt::v8::type_identity<unsigned char&>::type>, unsigned char&)'
C:/TDM-GCC-64/bin/../lib/gcc/x86_64-w64-mingw32/9.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: obj/CPUOpcodes.o:CPUOpcodes.cpp:(.text+0x3011): undefined reference to `void Logger::DoLog<unsigned char&>(Severity, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, fmt::v8::basic_format_string<char, fmt::v8::type_identity<unsigned char&>::type>, unsigned char&)'
...

fmt::format_string<Args...> fmt, Args&&...args我怀疑问题在于我如何处理DoLog. 我找不到任何问题。有什么我需要解决的吗?

标签: c++loggingvariadic-functionsfmt

解决方案


DoLog 的第三个参数应该只是一个字符串(我将输出更改为 std::cout 进行测试)

#include <map>
#include <iostream>
#include <string>

#include <fmt/format.h>


typedef enum Severity
{
    LOG_INFO = 0,
    LOG_WARNING,
    LOG_ERROR
} Severity;

static const std::string severity_str[3] = 
{
    "INFO",
    "WARNING",
    "ERROR"
};

class Logger
{
public:
    Logger() = default;
    ~Logger() = default;

    template<typename... args_t>
    void DoLog(Severity severity, const std::string& context, const std::string& fmt, args_t&&... args)
    {
        std::cout << fmt::format("[{:<7}] [{}] {}", severity_str[severity], context, fmt::format(fmt, std::forward<args_t>(args)...)) << std::endl;
    }

};


int main()
{
    Logger log;
    log.DoLog(LOG_INFO, "0", "Yo");
    log.DoLog(LOG_INFO, "1", "Hello {}", 42);
    log.DoLog(LOG_ERROR, "2", "Word {0:02X}", 0xFF);
    log.DoLog(LOG_WARNING, "3", "! {} {}", 4, 5);
    uint8_t opcode = 0xDD;
    log.DoLog(LOG_ERROR, "CPU::HandlePrefixCB", "Unknown opcode: {0:02X}", opcode);
    uint8_t& ref = opcode;
    log.DoLog(LOG_ERROR, "CPU::HandlePrefixCB", "Unknown opcode: {0:02X}", ref);
    return 0;
}

推荐阅读