diff --git a/include/fmt/base.h b/include/fmt/base.h index 052c66bf..51bab05e 100644 --- a/include/fmt/base.h +++ b/include/fmt/base.h @@ -2870,11 +2870,12 @@ FMT_CONSTEXPR inline auto check_char_specs(const format_specs& specs) -> bool { return true; } -template class format_string_checker { +template struct arg_pack {}; + +template +class format_string_checker { private: using parse_context_type = compile_parse_context; - static constexpr int num_args = sizeof...(Args); - static constexpr int num_named_args = count_statically_named_args(); // Format specifiers parsing function. // In the future basic_format_parse_context will replace compile_parse_context @@ -2882,21 +2883,23 @@ template class format_string_checker { // needed for compile-time checks: https://godbolt.org/z/GvWzcTjh1. using parse_func = const Char* (*)(parse_context_type&); - type types_[num_args > 0 ? static_cast(num_args) : 1]; + type types_[NUM_ARGS > 0 ? NUM_ARGS : 1]; parse_context_type context_; - parse_func parse_funcs_[num_args > 0 ? static_cast(num_args) : 1]; - named_arg_info named_args_[num_named_args > 0 ? num_named_args : 1]; + parse_func parse_funcs_[NUM_ARGS > 0 ? NUM_ARGS : 1]; + named_arg_info named_args_[NUM_NAMED_ARGS > 0 ? NUM_NAMED_ARGS : 1]; public: - explicit FMT_CONSTEXPR format_string_checker(basic_string_view fmt) - : types_{mapped_type_constant>::value...}, - context_(fmt, num_args, types_), - parse_funcs_{&parse_format_specs...}, + template + explicit FMT_CONSTEXPR format_string_checker(basic_string_view fmt, + arg_pack) + : types_{mapped_type_constant>::value...}, + context_(fmt, NUM_ARGS, types_), + parse_funcs_{&parse_format_specs...}, named_args_{} { using dummy = int[]; int arg_index = 0, named_arg_index = 0; - (void)dummy{0, (init_statically_named_arg(named_args_, arg_index, - named_arg_index), + (void)dummy{0, (init_statically_named_arg(named_args_, arg_index, + named_arg_index), 0)...}; ignore_unused(arg_index, named_arg_index); } @@ -2908,7 +2911,7 @@ template class format_string_checker { return context_.check_arg_id(id), id; } FMT_CONSTEXPR auto on_arg_id(basic_string_view id) -> int { - for (int i = 0; i < num_named_args; ++i) { + for (int i = 0; i < NUM_NAMED_ARGS; ++i) { if (named_args_[i].name == id) return i; } on_error("named argument is not found"); @@ -2923,7 +2926,7 @@ template class format_string_checker { -> const Char* { context_.advance_to(begin); // id >= 0 check is a workaround for gcc 10 bug (#2065). - return id >= 0 && id < num_args ? parse_funcs_[id](context_) : begin; + return id >= 0 && id < NUM_ARGS ? parse_funcs_[id](context_) : begin; } FMT_NORETURN FMT_CONSTEXPR void on_error(const char* message) { @@ -3009,7 +3012,9 @@ template class basic_format_string { private: basic_string_view str_; - using checker = detail::format_string_checker...>; + using checker = detail::format_string_checker< + Char, static_cast(sizeof...(Args)), + detail::count_statically_named_args()>; FMT_CONSTEXPR FMT_ALWAYS_INLINE static void check( basic_string_view fmt) { @@ -3019,7 +3024,7 @@ template class basic_format_string { std::is_reference::value)...>() == 0, "passing views as lvalues is disallowed"); if (count_named_args() == count_statically_named_args()) - parse_format_string(fmt, checker(fmt)); + parse_format_string(fmt, checker(fmt, arg_pack())); } public: