@@ -267,13 +267,15 @@ constexpr auto parse_text(basic_string_view<Char> str, size_t pos) -> size_t {
267267 return pos;
268268}
269269
270- template <typename Args, size_t POS, int ID, typename S>
270+ template <typename Args, size_t POS, int ID, bool DYNAMIC_NAMES, typename S>
271271constexpr auto compile_format_string (S fmt);
272272
273- template <typename Args, size_t POS, int ID, typename T, typename S>
273+ template <typename Args, size_t POS, int ID, bool DYNAMIC_NAMES, typename T,
274+ typename S>
274275constexpr auto parse_tail (T head, S fmt) {
275276 if constexpr (POS != basic_string_view<typename S::char_type>(fmt).size ()) {
276- constexpr auto tail = compile_format_string<Args, POS, ID>(fmt);
277+ constexpr auto tail =
278+ compile_format_string<Args, POS, ID, DYNAMIC_NAMES>(fmt);
277279 if constexpr (std::is_same<remove_cvref_t <decltype (tail)>,
278280 unknown_format>())
279281 return tail;
@@ -347,13 +349,13 @@ struct field_type<T, enable_if_t<detail::is_named_arg<T>::value>> {
347349};
348350
349351template <typename T, typename Args, size_t END_POS, int ARG_INDEX, int NEXT_ID,
350- typename S>
352+ bool DYNAMIC_NAMES, typename S>
351353constexpr auto parse_replacement_field_then_tail (S fmt) {
352354 using char_type = typename S::char_type;
353355 constexpr auto str = basic_string_view<char_type>(fmt);
354356 constexpr char_type c = END_POS != str.size () ? str[END_POS] : char_type ();
355357 if constexpr (c == ' }' ) {
356- return parse_tail<Args, END_POS + 1 , NEXT_ID>(
358+ return parse_tail<Args, END_POS + 1 , NEXT_ID, DYNAMIC_NAMES >(
357359 field<char_type, typename field_type<T>::type, ARG_INDEX>(), fmt);
358360 } else if constexpr (c != ' :' ) {
359361 FMT_THROW (format_error (" expected ':'" ));
@@ -364,7 +366,8 @@ constexpr auto parse_replacement_field_then_tail(S fmt) {
364366 FMT_THROW (format_error (" expected '}'" ));
365367 return 0 ;
366368 } else {
367- return parse_tail<Args, result.end + 1 , result.next_arg_id >(
369+ return parse_tail<Args, result.end + 1 , result.next_arg_id ,
370+ DYNAMIC_NAMES>(
368371 spec_field<char_type, typename field_type<T>::type, ARG_INDEX>{
369372 result.fmt },
370373 fmt);
@@ -374,22 +377,23 @@ constexpr auto parse_replacement_field_then_tail(S fmt) {
374377
375378// Compiles a non-empty format string and returns the compiled representation
376379// or unknown_format() on unrecognized input.
377- template <typename Args, size_t POS, int ID, typename S>
380+ template <typename Args, size_t POS, int ID, bool DYNAMIC_NAMES, typename S>
378381constexpr auto compile_format_string (S fmt) {
379382 using char_type = typename S::char_type;
380383 constexpr auto str = basic_string_view<char_type>(fmt);
381384 if constexpr (str[POS] == ' {' ) {
382385 if constexpr (POS + 1 == str.size ())
383386 FMT_THROW (format_error (" unmatched '{' in format string" ));
384387 if constexpr (str[POS + 1 ] == ' {' ) {
385- return parse_tail<Args, POS + 2 , ID>(make_text (str, POS, 1 ), fmt);
388+ return parse_tail<Args, POS + 2 , ID, DYNAMIC_NAMES>(
389+ make_text (str, POS, 1 ), fmt);
386390 } else if constexpr (str[POS + 1 ] == ' }' || str[POS + 1 ] == ' :' ) {
387391 static_assert (ID != manual_indexing_id,
388392 " cannot switch from manual to automatic argument indexing" );
389393 constexpr auto next_id =
390394 ID != manual_indexing_id ? ID + 1 : manual_indexing_id;
391- return parse_replacement_field_then_tail<get_type<ID, Args>, Args,
392- POS + 1 , ID, next_id>(fmt);
395+ return parse_replacement_field_then_tail<
396+ get_type<ID, Args>, Args, POS + 1 , ID, next_id, DYNAMIC_NAMES >(fmt);
393397 } else {
394398 constexpr auto arg_id_result =
395399 parse_arg_id<ID>(str.data () + POS + 1 , str.data () + str.size ());
@@ -402,21 +406,24 @@ constexpr auto compile_format_string(S fmt) {
402406 ID == manual_indexing_id || ID == 0 ,
403407 " cannot switch from automatic to manual argument indexing" );
404408 constexpr auto arg_index = arg_id_result.arg_id .index ;
405- return parse_replacement_field_then_tail<get_type<arg_index, Args>,
406- Args, arg_id_end_pos,
407- arg_index, manual_indexing_id>(
408- fmt);
409+ return parse_replacement_field_then_tail<
410+ get_type<arg_index, Args>, Args, arg_id_end_pos, arg_index,
411+ manual_indexing_id, DYNAMIC_NAMES>(fmt);
409412 } else if constexpr (arg_id_result.kind == arg_id_kind::name) {
410413 constexpr auto arg_index =
411414 get_arg_index_by_name (arg_id_result.arg_id .name , Args{});
415+
416+ static_assert (arg_index >= 0 || DYNAMIC_NAMES,
417+ " named argument not found" );
418+
412419 if constexpr (arg_index >= 0 ) {
413420 constexpr auto next_id =
414421 ID != manual_indexing_id ? ID + 1 : manual_indexing_id;
415422 return parse_replacement_field_then_tail<
416423 decltype (get_type<arg_index, Args>::value), Args, arg_id_end_pos,
417- arg_index, next_id>(fmt);
424+ arg_index, next_id, DYNAMIC_NAMES >(fmt);
418425 } else if constexpr (c == ' }' ) {
419- return parse_tail<Args, arg_id_end_pos + 1 , ID>(
426+ return parse_tail<Args, arg_id_end_pos + 1 , ID, DYNAMIC_NAMES >(
420427 runtime_named_field<char_type>{arg_id_result.arg_id .name }, fmt);
421428 } else if constexpr (c == ' :' ) {
422429 return unknown_format (); // no type info for specs parsing
@@ -426,13 +433,16 @@ constexpr auto compile_format_string(S fmt) {
426433 } else if constexpr (str[POS] == ' }' ) {
427434 if constexpr (POS + 1 == str.size ())
428435 FMT_THROW (format_error (" unmatched '}' in format string" ));
429- return parse_tail<Args, POS + 2 , ID>(make_text (str, POS, 1 ), fmt);
436+ return parse_tail<Args, POS + 2 , ID, DYNAMIC_NAMES>(make_text (str, POS, 1 ),
437+ fmt);
430438 } else {
431439 constexpr auto end = parse_text (str, POS + 1 );
432440 if constexpr (end - POS > 1 ) {
433- return parse_tail<Args, end, ID>(make_text (str, POS, end - POS), fmt);
441+ return parse_tail<Args, end, ID, DYNAMIC_NAMES>(
442+ make_text (str, POS, end - POS), fmt);
434443 } else {
435- return parse_tail<Args, end, ID>(code_unit<char_type>{str[POS]}, fmt);
444+ return parse_tail<Args, end, ID, DYNAMIC_NAMES>(
445+ code_unit<char_type>{str[POS]}, fmt);
436446 }
437447 }
438448}
@@ -444,8 +454,11 @@ constexpr auto compile(S fmt) {
444454 if constexpr (str.size () == 0 ) {
445455 return detail::make_text (str, 0 , 0 );
446456 } else {
447- constexpr auto result =
448- detail::compile_format_string<detail::type_list<Args...>, 0 , 0 >(fmt);
457+ constexpr int num_static_named_args =
458+ detail::count_static_named_args<Args...>();
459+ constexpr auto result = detail::compile_format_string<
460+ detail::type_list<Args...>, 0 , 0 ,
461+ num_static_named_args != detail::count_named_args<Args...>()>(fmt);
449462 return result;
450463 }
451464}
0 commit comments