C 格式字符串宏

C++ Format String Macro

本文关键字:字符串 格式      更新时间:2023-10-16

我的功能可以格式化字符串:

template<typename ... Args>
inline std::string format(const std::string & format, Args ... args)
{
    std::size_t size = MINIGINE_FORMAT_PRINTF(nullptr, 0, format.c_str(), args ...) + 1; // +1 for NULL terminated
    std::unique_ptr<char[]> buf( new char[ size ] );
    MINIGINE_FORMAT_PRINTF(buf.get(), size, format.c_str(), args ...);
    return std::string(buf.get(), buf.get() + size - 1); // -1 we don't want NULL terminated
}

问题是当我调用此功能时:

format("%d", "");

警告显示在模板函数中,而不是在呼叫站点中显示。

是否可以在呼叫站点中显示格式警告,而不是模板函数?

我提出了解决我问题的解决方案。如果编译器为格式生成警告,则在调用宏的行中显示警告。

我已经测试了模板格式函数和下面的宏:https://godbolt.org/当模板函数的格式参数为const char*而不是std :: string

时,它们似乎都会生成相同的代码。
#pragma once
#include <string>
#include <memory>
#ifdef _MSC_VER
    #define MINIGINE_FORMAT_PRINTF _snprintf
#else
    #define MINIGINE_FORMAT_PRINTF snprintf
#endif
#define MINIGINE_FORMAT(format, ...) 
/*Capture everything by reference*/[&] /*No arguments*/() 
{ 
    std::size_t size = MINIGINE_FORMAT_PRINTF(nullptr, 0, format, __VA_ARGS__) + 1; 
    std::unique_ptr<char[]> buf( new char[ size ] ); 
    MINIGINE_FORMAT_PRINTF(buf.get(), size, format, __VA_ARGS__); 
    return std::string(buf.get(), buf.get() + size - 1); 
} /*Call the lambda*/()

是否可以在呼叫站点中显示格式警告,而不是在模板函数中显示?

是的,您可以使用constexpr格式字符串检查无宏(几乎)进行此操作。例如:

template <typename S, typename... Args>
inline std::string format(const S &fmt, const Args &... args) {
  constexpr bool is_valid = check_format_string<Args...>(fmt); 
  // Do formatting.
}

其中check_format_string是一个constexpr函数,该功能解析并检查格式字符串,而S是编译时格式字符串。

该技术用于{fmt}库,该库实现了类似python的格式:

// test.cc
#define FMT_STRING_ALIAS 1
#include <fmt/format.h>
std::string s = format(fmt("{2}"), 42);

编译并观察呼叫站点的预期错误:

$ c++ -Iinclude -std=c++14 test.cc
...
test.cc:4:17: note: in instantiation of function template specialization 'fmt::v5::format<S, int>' requested here
std::string s = format(fmt("{2}"), 42);
                ^
include/fmt/core.h:778:19: note: non-constexpr function 'on_error' cannot be used in a constant expression
    ErrorHandler::on_error(message);
                  ^
include/fmt/format.h:2226:16: note: in call to '&checker.context_->on_error(&"argument index out of range"[0])'
      context_.on_error("argument index out of range");
               ^

您仍然需要一个宏来构建编译时字符串,但这在C 20中是不必要的。

免责声明:我是{fmt}的作者。