如何为模板类内的结构体创建std::formatter以支持std::print?
问题描述
我需要为模板类ThreeStack中定义的StackProperties结构体实现std::formatter,这样就能用std::print打印该结构体的实例。
我的ThreeStack类代码如下:
template <typename ValueType, std::size_t SizeOfEachStack> requires (SizeOfEachStack > 0) class ThreeStack { public: struct StackProperties { std::size_t min_index{0}; std::size_t max_index{0}; std::size_t current_index{0}; }; ThreeStack() { for(std::size_t stack_number = 0; stack_number < num_of_stacks; stack_number++) { stack_properties.at(stack_number).min_index = stack_number * SizeOfEachStack; stack_properties.at(stack_number).current_index = stack_properties.at(stack_number).min_index; stack_properties.at(stack_number).max_index = stack_properties.at(stack_number).min_index + SizeOfEachStack - 1; } }; // Print function to print the internal arrays. void print_internal_arrays() { for(std::size_t stack_number = 0; stack_number < num_of_stacks; stack_number++) { std::print("Stack {}: {}\n", stack_number, stack_properties.at(stack_number)); } } private: static constexpr size_t num_of_stacks{3}; std::array<ThreeStack::StackProperties, num_of_stacks> stack_properties{}; };
我尝试编写的std::formatter无法正常工作:
// Create a std::formatter for the ThreeStack::StackProperties struct for any ThreeStack<ValueType, SizeOfEachStack>. template <typename ValueType, std::size_t SizeOfEachStack> struct std::formatter<ThreeStack<ValueType, SizeOfEachStack>::StackProperties> { constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } template <typename FormatContext> auto format(const ThreeStack<ValueType, SizeOfEachStack>::StackProperties& stack_properties, FormatContext& ctx) { return format_to(ctx.out(), "min_index: {}, max_index: {}, current_index: {}", stack_properties.min_index, stack_properties.max_index, stack_properties.current_index); } };
编译时出现以下错误:
<source>:43:78: error: type/value mismatch at argument 1 in template parameter list for 'template<class _Tp, class _CharT> struct std::formatter' 43 | struct std::formatter<ThreeStack<ValueType, SizeOfEachStack>::StackProperties> | ^ <source>:43:78: note: expected a type, got 'ThreeStack<ValueType, SizeOfEachStack>::StackProperties' <source>:43:13: error: template class without a name 43 | struct std::formatter<ThreeStack<ValueType, SizeOfEachStack>::StackProperties> | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Compiler returned: 1
解决方案
编译错误的核心原因是:在模板参数中使用ThreeStack<ValueType, SizeOfEachStack>::StackProperties时,编译器无法确定这是一个类型(它可能被解析为值或成员),需要用typename关键字显式声明这是一个类型。另外,std::formatter本身是双模板参数结构体(第二个参数默认是char),需要匹配其完整模板参数列表。
修正后的std::formatter实现
template <typename ValueType, std::size_t SizeOfEachStack, typename CharT> struct std::formatter<typename ThreeStack<ValueType, SizeOfEachStack>::StackProperties, CharT> { constexpr auto parse(std::format_parse_context& ctx) { auto it = ctx.begin(); if (it != ctx.end() && *it != '}') { throw std::format_error("invalid format for StackProperties"); } return it; } template <typename FormatContext> auto format(const typename ThreeStack<ValueType, SizeOfEachStack>::StackProperties& props, FormatContext& ctx) { return std::format_to(ctx.out(), "min_index: {}, max_index: {}, current_index: {}", props.min_index, props.max_index, props.current_index); } };
关键修正点
- 添加
typename关键字:typename ThreeStack<ValueType, SizeOfEachStack>::StackProperties明确告诉编译器这是一个类型,解决"type/value mismatch"错误。 - 匹配完整模板参数:
std::formatter的第二个模板参数是字符类型(默认char),将其加入模板参数列表,保证特化的正确性。 - 完善
parse方法:正确处理格式字符串解析,避免非法格式导致的未定义行为。
完整可编译代码示例
#include <iostream> #include <format> #include <array> template <typename ValueType, std::size_t SizeOfEachStack> requires (SizeOfEachStack > 0) class ThreeStack { public: struct StackProperties { std::size_t min_index{0}; std::size_t max_index{0}; std::size_t current_index{0}; }; ThreeStack() { for(std::size_t stack_number = 0; stack_number < num_of_stacks; stack_number++) { stack_properties.at(stack_number).min_index = stack_number * SizeOfEachStack; stack_properties.at(stack_number).current_index = stack_properties.at(stack_number).min_index; stack_properties.at(stack_number).max_index = stack_properties.at(stack_number).min_index + SizeOfEachStack - 1; } }; void print_internal_arrays() { for(std::size_t stack_number = 0; stack_number < num_of_stacks; stack_number++) { std::print("Stack {}: {}\n", stack_number, stack_properties.at(stack_number)); } } private: static constexpr size_t num_of_stacks{3}; std::array<ThreeStack::StackProperties, num_of_stacks> stack_properties{}; }; template <typename ValueType, std::size_t SizeOfEachStack, typename CharT> struct std::formatter<typename ThreeStack<ValueType, SizeOfEachStack>::StackProperties, CharT> { constexpr auto parse(std::format_parse_context& ctx) { auto it = ctx.begin(); if (it != ctx.end() && *it != '}') { throw std::format_error("invalid format for StackProperties"); } return it; } template <typename FormatContext> auto format(const typename ThreeStack<ValueType, SizeOfEachStack>::StackProperties& props, FormatContext& ctx) { return std::format_to(ctx.out(), "min_index: {}, max_index: {}, current_index: {}", props.min_index, props.max_index, props.current_index); } }; int main() { ThreeStack<int, 5> stack; stack.print_internal_arrays(); return 0; }
这段代码编译后会输出:
Stack 0: min_index: 0, max_index: 4, current_index: 0 Stack 1: min_index: 5, max_index: 9, current_index: 5 Stack 2: min_index: 10, max_index: 14, current_index: 10
内容的提问来源于stack exchange,提问作者sakcakoca
相关产品推荐
相关产品推荐

