我正在尝试以下操作(链接):
#include <string>
#include <format> // For std::format
#include <fmt/format.h> // For fmt::format
#include <ranges>
#include <functional>
struct Point {
int x;
int y;
};
#ifdef USE_FMT
template<typename T>
struct Formatter : public fmt::formatter<T> {};
using context = fmt::format_context;
#else
template<typename T>
struct Formatter : public std::formatter<T> {};
using context = std::format_context;
#endif
template <>
struct Formatter<Point>: Formatter<std::string>
{
auto format(Point x,
context& ctx) const
{
return Formatter<std::string>::format(std::to_string(x.x) + "us", ctx);
}
};
int main() {
Point xx {2,3};
std::cout << std::format("{}", xx); // assuming using std
return 0;
}
但是编译失败。如上面的代码所示,我想让开发人员使用
struct Formatter
自定义格式,然后后端可以选择要采用的后端解决方案。
失败的任何原因以及可能的解决方案?
编译器错误:
包含在文件中 /opt/compiler-explorer/gcc-trunk-20240207/include/c++/14.0.1/ostream:43, 来自/opt/compiler-explorer/gcc-trunk-20240207/include/c++/14.0.1/iostream:41, 来自:1:/opt/compiler-explorer/gcc-trunk-20240207/include/c++/14.0.1/format: 在“class std::__format::_Checking_scanner
”的实例化中: /opt/compiler-explorer/gcc-trunk-20240207/include/c++/14.0.1/format:4174:4: 需要 'consteval std::basic_format_string<_CharT, _Args>::basic_format_string(const _Tp&) [with _Tp = char [3]; _CharT = 字符;第 4174 章__scanner(_M_str); | ^~~~~~~~~ :38:29:需要从这里 38 | std::cout << std::format("{}", xx); // assuming using std | ~~~~~~~~~~~^~~~~~~~~~ /opt/compiler-explorer/gcc-trunk-20240207/include/c++/14.0.1/format:4030:10: error: static assertion failed: std::formatter must be specialized for each type being formatted 4030 |
(is_default_constructible_v> && ...),
非专用格式化程序的默认设置将引发此类错误,表明您实际上尚未为该类型专门化格式化程序。这记录在
std::formatter
:
对于未启用专门化
的所有类型 T 和 CharT,该专门化是完整类型并且被禁用。std::formatter<T, CharT>
禁用的专业化不满足Formatter要求,以下均为
:false
这里的问题是,您没有专门化
std::formatter
,而是定义派生自 std::formatter
的 own类模板并专门化 that。当您调用
std::format
时,它无法找到您的 Formatter
专业化。
这同样适用于
fmt::format
。
此外,尽管有基于宏
std::format
选择格式库的逻辑,但您的程序在这里始终使用USE_FMT
。如果您定义该宏,您将遇到进一步的问题,因为 std::format
不会寻找 fmt::formatter
专业化。
您需要直接专业化
std::formatter
(或fmt::formatter
)。以下是如何干净利落地做到这一点:
#include <iostream>
#include <string>
#ifdef USE_FMT
# include <fmt/format.h> // For fmt::format
# define FMT_NAMESPACE fmt
#else
# include <format> // For std::format
# define FMT_NAMESPACE std
#endif
using FMT_NAMESPACE::format;
struct Point {
int x;
int y;
};
template <>
struct FMT_NAMESPACE::formatter<Point> : formatter<std::string>
{
auto format(Point x, format_context& ctx) const
{
return formatter<std::string>::format(std::to_string(x.x) + "us", ctx);
}
};
int main()
{
Point xx {2,3};
std::cout << format("{}", xx);
}