使用抽象自定义格式化程序

问题描述 投票:0回答:1

我正在尝试以下操作(链接):

#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> && ...),

c++ std c++20 fmt
1个回答
0
投票

非专用格式化程序的默认设置将引发此类错误,表明您实际上尚未为该类型专门化格式化程序。这记录在

std::formatter
:

对于未启用专门化

std::formatter<T, CharT>
的所有类型 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);
}
© www.soinside.com 2019 - 2024. All rights reserved.