例如,我有一个自定义类型
struct custom_type
{
double value;
};
Run Code Online (Sandbox Code Playgroud)
我想为此类型设置自定义FMT格式器。我执行以下操作,并且有效:
namespace fmt
{
template <>
struct formatter<custom_type> {
template <typename ParseContext>
constexpr auto parse(ParseContext &ctx) {
return ctx.begin();
};
template <typename FormatContext>
auto format(const custom_type &v, FormatContext &ctx) {
return format_to(ctx.begin(), "{}", v.value);
}
};
Run Code Online (Sandbox Code Playgroud)
但是问题是,输出格式是由带有此"{}"表达式的模板代码设置的。我想给用户一个机会自己定义格式字符串。
例如:
custom_type v = 10.0;
std::cout << fmt::format("{}", v) << std::endl; // 10
std::cout << fmt::format("{:+f}", v) << std::endl; // 10.000000
Run Code Online (Sandbox Code Playgroud)
我怎样才能做到这一点?
目前,当我设置自定义格式字符串时,
what(): unknown format specifier
Run Code Online (Sandbox Code Playgroud) 我使用基于 fmt 的记录器以及可选的彩色打印 - 它依赖于 ANSI 颜色命令。
不幸的是,在 Windows 10 上它默认被禁用。我知道如何启用它,但我仍然想知道如何测试控制台是否支持 ANSI 命令。有人知道吗?
我正在尝试将std::chrono::duration对象格式化为 HH:MM::SS 格式,例如 16:42:02 是小时 (16)、分钟 (42) 和秒 (2)。
该库fmt为此提供了有用的格式说明符:
using namespace std::chrono;
auto start = high_resolution_clock::now();
auto end = start + 4s;
fmt::print("{:%H:%M:%S} \n", end);
Run Code Online (Sandbox Code Playgroud)
不幸的是,它以小数形式打印秒
16:58:55.359425076
Run Code Online (Sandbox Code Playgroud)
我想将其四舍五入到最接近的整数,但无法弄清楚在哪里放置精度说明符(精度 2 仅在测试方面):
fmt::print("{:.2%H:%M:%S} \n", end); // error
fmt::print("{:.2f%H:%M:%S} \n", end); // error
fmt::print("{:%H:%M:.2%S} \n", end); // nonsense: 17:07:.202.454873454
Run Code Online (Sandbox Code Playgroud)
我盯着chrono 格式规范的细节有点迷失......
上面的编译器资源管理器示例在这里。
我可以使用fmt库打印 C++ 类的对象吗?
fmt::print("The object is {}.", obj);
Run Code Online (Sandbox Code Playgroud) 我有很多从同一个基类派生的类,并且我试图避免为所有派生类编写格式化程序。我尝试只为基类实现 std::formatter,但将派生类对象/引用传递给 std::format 将触发编译错误。
C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.32.31326\include\format(1496): 错误 C2665: 'std::_Format_arg_traits<_Context>::_Phony_basic_format_arg_constructor': 没有5 个重载可以使用 [ _Context=std::format_context ] 转换所有参数类型...
最小代码如下:
#include <format>
#include <iostream>
#include <string>
using namespace std;
struct Base
{
virtual string ToString()
{
return "Base";
}
};
struct D1 : public Base
{
string ToString() override
{
return "D1";
}
};
template <typename CharT> struct ::std::formatter<Base, CharT> : ::std::formatter<::std::string>
{
// parse is inherited from formatter<string>.
template <typename FormatContext> auto format(Base &e, FormatContext &ctx) const
{
::std::string name = …Run Code Online (Sandbox Code Playgroud) 在 C++20 中 - 如何使用户定义的类型与 兼容std::format?
例如,假设我有一个名为 的类型Point:
struct Point {
int x;
int y;
};
Run Code Online (Sandbox Code Playgroud)
其operator<<定义:
inline std::ostream&
operator<<(std::ostream& o, Point pt)
{ return o << "[" << pt.x << << ", " << pt.y << "]"; }
Run Code Online (Sandbox Code Playgroud)
那么下面的程序会输出Hello [3, 4]!吗?
int main() {
Point pt{3,4};
std::cout << std::format("Hello {}!\n", pt);
}
Run Code Online (Sandbox Code Playgroud)
如果是 - 为什么以及如何?
如果不是 - 我必须在 to 的定义中添加什么Point才能使其工作?
我知道 c++20 格式提案是libfmt部分的形式化,而 libfmt 是该形式化的兼容实现。但是,据我所知,libfmt 提供的功能超出了 c++20 标准中指定的功能。有哪些附加功能?
另外,主要编译器供应商是简单地包含 libfmt 的一个子集还是重新实现它?
我想在 C++ 中创建一个简单的日志函数,它将代码位置添加到日志消息中。我想避免使用宏以及__FILE__&的使用__LINE__。
请注意,该format字符串始终是编译时字符串,我希望在编译时进行尽可能多的计算(目标机器是一个小型 MCU)。
我可以source_location通过experimental/source_location. 我也可以使用{fmt}。
我从这个开始。目前,我有以下几点:
#include <fmt/format.h>
#include <experimental/source_location>
using source_location = std::experimental::source_location;
void vlog(fmt::string_view format, fmt::format_args args)
{
fmt::vprint(format, args);
}
template <typename S, typename... Args>
void log(const S& format, const source_location& location, Args&&... args)
{
vlog(format, fmt::make_args_checked<fmt::string_view, uint32_t, Args...>(format, location.file_name(), location.line(), args...));
}
#define MY_LOG(format, ...) log(FMT_STRING("{},{}, " format), source_location::current(), __VA_ARGS__)
int main() {
MY_LOG("invalid squishiness: {}", 42);
}
Run Code Online (Sandbox Code Playgroud)
哪个产量正确./example.cpp,20, …
我有一个简单的类,它有一个 tostring() 方法:
class MyClass {
public:
std::string tostring() const;
static iterator begin();
static iterator end();
};
Run Code Online (Sandbox Code Playgroud)
虽然我现在正在使用 fmt 库,但这段代码是从没有的代码中移植过来的,所以许多遗留类都实现了 tostring() 方法,而且我有一个模板可以为任何类生成 fmt::formatter有那个方法 它一直运行良好。
然而,这个特殊的类也有开始/结束功能。但是,它们是静态的(此类类似于枚举,您可以遍历所有可能的值),并且与格式无关。
一切都很好,直到我需要为一些不同的代码包含 fmt/ranges.h。问题是有一个范围格式化程序可以看到开始/结束函数并希望将类格式化为范围。现在,如果我尝试格式化类,我会得到格式化程序的一个模棱两可的实例(一个用于我要使用的模板,一个用于范围格式化程序)。
有没有办法让范围格式化程序忽略这个类?
一个完整的例子是:
#include <type_traits>
#include <utility>
#include <string>
#include <vector>
#include <fmt/format.h>
// #include <fmt/ranges.h>
// Create formatter for any class that has a tostring() method
template <typename T>
struct has_tostring_member {
private:
template <typename U>
static std::true_type test( decltype(&U::tostring) );
template <typename U>
static std::false_type test(...);
public:
using result = decltype(test<T>(0) ); …Run Code Online (Sandbox Code Playgroud) 使用fmt库,您可以轻松格式化已定义的类型operator<<。正如这里所解释的,您可以ostream_formatter使用一行代码进行扩展:
template <> struct fmt::formatter<Foo> : ostream_formatter {};
Run Code Online (Sandbox Code Playgroud)
现在你可以这样做:
fmt::format("Foo is {}", Foo());
Run Code Online (Sandbox Code Playgroud)
类似的事情可能吗std::format()?我有已经定义的类型operator<<,所以我想开始将它们与std::format().
如果我尝试编写自己的格式化程序,我不知道如何ostream从成员函数中的参数中获取 an format()。
template <> struct fmt::formatter<Foo> : ostream_formatter {};
Run Code Online (Sandbox Code Playgroud)
直接编写格式化程序而不依赖于 是否更好operator<<?