查找可变参数列表的字符串格式指定符

finding string format specifiers of variable argument list

本文关键字:格式 字符串 变参 参数 列表 查找      更新时间:2023-10-16

我具有调用我的logger(spdlog(方法的该日志功能:

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

我想将我的记录器(由g_fileloggre代表(更改为另一个记录器。不幸的是," fmt"字符串包含" {}",它是变量的占位符" args"。我想通过正确的格式指定符(%s,%zu,%d等...(更改这些" {}">

您可以给我一个快速安全的解决方案,以生成一个用变量的正确格式替换" {}"的字符串。

否则,SPDLog是一个很棒的日志记录API,但是由于其API已损坏,我们决定选择另一个记录器,例如,在CentOS中,API旧了,而在Gentoo中,它是更新的,代码不会编译。

创建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";
}
 // .....

创建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的宏。