我正在使用一种选择加入方法,可以通过自定义类的 std::cout 和 fmt::print 打印到控制台。为此,我创建了一个std::string to_string(const T& value)
在一般情况下未定义的函数。专业课程应该:
to_string(const MyType& t)
struct printable< MyType >: public std::true_type{}
这将依次激活std::ostream
并 fmt::formatter
自动专门针对每种printable
类型。一个完整的例子是这样的:
#include <fmt/format.h>
#include <fmt/ostream.h>
#include <fmt/ranges.h>
#include <concepts>
#include <iostream>
#include <string>
#include <vector>
namespace common {
template <typename T>
std::string to_string(const T& value);
template <typename T>
struct printable : std::false_type {};
template <typename T>
constexpr bool printable_v = printable<T>::value;
} // namespace common
template <typename T>
requires(common::printable_v<T>)
auto& operator<<(std::ostream& os, const T& value) {
return os << common::to_string(value);
}
template <class T>
requires(common::printable_v<T>)
struct fmt::formatter<T> : public fmt::ostream_formatter {};
struct MyClass {
std::vector<int> v{1, 2, 3, 4, 5};
auto begin() { return v.begin(); }
auto begin() const { return v.begin(); }
auto end() { return v.end(); }
auto end() const { return v.end(); }
};
namespace common {
inline std::string to_string(const MyClass& c) {
return fmt::format("{}", c.v);
}
template <>
struct printable<MyClass> : std::true_type {};
} // namespace common
int main() {
// this works:
// std::cout << common::to_string(MyClass{});
// this doesn't:
fmt::format("{}", MyClass{});
}
Run Code Online (Sandbox Code Playgroud)
然而,对于fmt
v10.1.1,这会带来一些神秘的错误消息 (clang-17):
/opt/compiler-explorer/gcc-13.2.0/lib/gcc/x86_64-linux-gnu/13.2.0/../../../../include/c++/13.2.0/type_traits:1048:21: error: static assertion failed due to requirement 'std::__is_complete_or_unbounded(std::__type_identity<fmt::formatter<MyClass, char, void>>{})': template argument must be a complete class or an unbounded array
1048 | static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}),
Run Code Online (Sandbox Code Playgroud)
和
<source>:55:17: error: call to consteval function 'fmt::basic_format_string<char, MyClass>::basic_format_string<char[3], 0>' is not a constant expression
55 | fmt::format("{}", MyClass{});
Run Code Online (Sandbox Code Playgroud)
为什么我的格式化程序方法不被接受,我怎样才能让 fmt 理解它?
MyClass
是一个范围(它有begin()
和end()
返回迭代器)。fmt
对于所有范围都有一个默认格式化程序,这与您尝试添加的格式化程序冲突。两者都不比另一个更专业,所以它是模棱两可的。
如果您禁用范围格式化程序,则只会使用您的范围格式化程序:
template <typename Char>
struct fmt::range_format_kind<MyClass, Char>
: std::integral_constant<fmt::range_format, fmt::range_format::disabled>
{ };
Run Code Online (Sandbox Code Playgroud)
不过,一旦你这样做了,你的实际定制to_string
就不太正确了(你会得到一个未定义的引用,common::to_string<MyClass>
因为你的函数不会被考虑),但这是一个单独的问题。
归档时间: |
|
查看次数: |
123 次 |
最近记录: |