@@ -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,
274+ bool DYNAMIC_NAMES, typename T, 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 = compile_format_string<Args, POS,
278+ ID, DYNAMIC_NAMES>(fmt);
277279 if constexpr (std::is_same<remove_cvref_t <decltype (tail)>,
278280 unknown_format>())
279281 return tail;
@@ -346,14 +348,14 @@ struct field_type<T, enable_if_t<detail::is_named_arg<T>::value>> {
346348 using type = remove_cvref_t <decltype (T::value)>;
347349};
348350
349- template <typename T, typename Args, size_t END_POS, int ARG_INDEX, int NEXT_ID,
350- typename S>
351+ template <typename T, typename Args, size_t END_POS, int ARG_INDEX,
352+ int NEXT_ID, 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 ,
370+ result.next_arg_id , DYNAMIC_NAMES>(
368371 spec_field<char_type, typename field_type<T>::type, ARG_INDEX>{
369372 result.fmt },
370373 fmt);
@@ -374,22 +377,24 @@ 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 ,
389+ ID, DYNAMIC_NAMES>(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;
391395 return parse_replacement_field_then_tail<get_type<ID, Args>, Args,
392- POS + 1 , ID, next_id>(fmt);
396+ POS + 1 , ID, next_id,
397+ DYNAMIC_NAMES>(fmt);
393398 } else {
394399 constexpr auto arg_id_result =
395400 parse_arg_id<ID>(str.data () + POS + 1 , str.data () + str.size ());
@@ -404,19 +409,25 @@ constexpr auto compile_format_string(S fmt) {
404409 constexpr auto arg_index = arg_id_result.arg_id .index ;
405410 return parse_replacement_field_then_tail<get_type<arg_index, Args>,
406411 Args, arg_id_end_pos,
407- arg_index, manual_indexing_id>(
412+ arg_index, manual_indexing_id,
413+ DYNAMIC_NAMES>(
408414 fmt);
409415 } else if constexpr (arg_id_result.kind == arg_id_kind::name) {
410416 constexpr auto arg_index =
411417 get_arg_index_by_name (arg_id_result.arg_id .name , Args{});
418+
419+ static_assert (
420+ arg_index >= 0 || DYNAMIC_NAMES,
421+ " named argument not found" );
422+
412423 if constexpr (arg_index >= 0 ) {
413424 constexpr auto next_id =
414425 ID != manual_indexing_id ? ID + 1 : manual_indexing_id;
415426 return parse_replacement_field_then_tail<
416427 decltype (get_type<arg_index, Args>::value), Args, arg_id_end_pos,
417- arg_index, next_id>(fmt);
428+ arg_index, next_id, DYNAMIC_NAMES >(fmt);
418429 } else if constexpr (c == ' }' ) {
419- return parse_tail<Args, arg_id_end_pos + 1 , ID>(
430+ return parse_tail<Args, arg_id_end_pos + 1 , ID, DYNAMIC_NAMES >(
420431 runtime_named_field<char_type>{arg_id_result.arg_id .name }, fmt);
421432 } else if constexpr (c == ' :' ) {
422433 return unknown_format (); // no type info for specs parsing
@@ -426,13 +437,16 @@ constexpr auto compile_format_string(S fmt) {
426437 } else if constexpr (str[POS] == ' }' ) {
427438 if constexpr (POS + 1 == str.size ())
428439 FMT_THROW (format_error (" unmatched '}' in format string" ));
429- return parse_tail<Args, POS + 2 , ID>(make_text (str, POS, 1 ), fmt);
440+ return parse_tail<Args, POS + 2 ,
441+ ID, DYNAMIC_NAMES>(make_text (str, POS, 1 ), fmt);
430442 } else {
431443 constexpr auto end = parse_text (str, POS + 1 );
432444 if constexpr (end - POS > 1 ) {
433- return parse_tail<Args, end, ID>(make_text (str, POS, end - POS), fmt);
445+ return parse_tail<Args, end,
446+ ID, DYNAMIC_NAMES>(make_text (str, POS, end - POS), fmt);
434447 } else {
435- return parse_tail<Args, end, ID>(code_unit<char_type>{str[POS]}, fmt);
448+ return parse_tail<Args, end,
449+ ID, DYNAMIC_NAMES>(code_unit<char_type>{str[POS]}, fmt);
436450 }
437451 }
438452}
@@ -444,8 +458,11 @@ constexpr auto compile(S fmt) {
444458 if constexpr (str.size () == 0 ) {
445459 return detail::make_text (str, 0 , 0 );
446460 } else {
461+ constexpr int num_static_named_args =
462+ detail::count_static_named_args<Args...>();
447463 constexpr auto result =
448- detail::compile_format_string<detail::type_list<Args...>, 0 , 0 >(fmt);
464+ detail::compile_format_string<detail::type_list<Args...>, 0 , 0 ,
465+ num_static_named_args != detail::count_named_args<Args...>()>(fmt);
449466 return result;
450467 }
451468}
@@ -585,4 +602,4 @@ template <size_t N> class static_format_result {
585602FMT_END_EXPORT
586603FMT_END_NAMESPACE
587604
588- #endif // FMT_COMPILE_H_
605+ #endif // FMT_COMPILE_H_
0 commit comments