查找变量参数列表的字符串格式说明符

时间:2018-04-27 10:57:12

标签: c++

我有这个Log函数调用我的logger(spdlog)方法:

template<typename... Args>
void Log(const char* fmt,
         const Args&... args)
{
    g_FileLogger->log(fmt, args...);
}

我想将我的记录器(spdlog,由g_FileLoggre表示)更改为另一个记录器。不幸的是,“fmt”字符串包含“{}”,它们是变量“args”的占位符。我想用正确的格式说明符(%s,%zu,%d等......)更改那些“{}”和其他记录器一样,我必须指定正确的格式说明符。

您能否给我一个快速安全的解决方案来生成一个字符串,用正确的变量格式说明符替换“{}”。

否则,spdlog是一个很好的日志API,但由于它的API已被破坏,我们决定选择另一个记录器,例如在Centos中API已经过时了,而在Gentoo中它更新,代码将无法编译。

2 个答案:

答案 0 :(得分:1)

创建format_converter功能

template<typename... Args>
std::string format_converter(const char* fmt,
                             const Args&... args)
{...}

解析fmt字符串并根据参数进行转换。

然后修改你的功能:

template<typename... Args>
void Log(const char* fmt,
         const Args&... args)
{
    auto new_fmt = format_converter(fmt, args...);
    new_logger->log( new_fmt, args... );
}

编辑:

format_converter中,模板函数可用于将参数类型转换为字符串。例如:

template< typename T >
const char* type_string( const T ); // primary template


const char* type_string( const char* ) // overload for c-string
{
    return "%s";
}

template<>
const char* type_string< double >( const double ) // partial specialization for double
{
    return "%d";
}

template<>
const char* type_string< int >( const int ) // partial specialization for int
{
    return "%i";
}

 // .....

答案 1 :(得分:1)

创建convert_format函数,将{..}替换为您指定的内容。创建一个包含要替换的数据的std::map<std::string, std::string>对象。

#include <string>
#include <map>

std::string convert_format(const std::string& format, std::map<std::string, std::string> format_map) {
    string ret;
    for (int x = 0; x != format.size(); ++x)  {
        if (format[x] == '{') {
            std::string key;
            ++x;
            for (; x != format.size(); ++x) {
                if (format[x] == '}') {
                    auto itr = format_map.find(key);
                    if (itr != format_map.end()) {
                        ret += (*itr).second;
                    }
                    break;
                } else {
                    key.push_back(format[x]);
                }
            }
        } else {
            ret.push_back(format[x]);
        }
    }

    return ret;
}

现在将Log函数修改为:

template<typename... Args>
void Log(const char* fmt,
         const Args&... args)
{
    // map that will contain the data.
    std::map<std::string, std::string> format_map;

    // IF you have an args named as number and a string
    // replaces {number} with %d
    format_map["number"] = "%d";

    // for replacing '{string}' with %s
    format_map["string"] = "%s"; // ... and so on

    auto new_fmt = convert_format(std::string(fmt), format_map);
    new_logger->log( new_fmt, args... );
}

编辑:我认为您需要一个将变量的名称和值传递给函数Log的宏。