From 5a1127b726879e21e5a9613fc620d08413d39054 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sun, 14 Mar 2021 09:08:08 -0700 Subject: [PATCH] Don't wrap named arg in cref and clarify docs --- include/fmt/args.h | 24 ++++++++---------------- include/fmt/core.h | 5 +++-- test/core-test.cc | 22 ++++------------------ 3 files changed, 15 insertions(+), 36 deletions(-) diff --git a/include/fmt/args.h b/include/fmt/args.h index 5891ea25..b55fbdb7 100644 --- a/include/fmt/args.h +++ b/include/fmt/args.h @@ -168,29 +168,21 @@ class dynamic_format_arg_store /** \rst Adds a reference to the argument into the dynamic store for later passing to - a formatting function. Supports named arguments wrapped in - ``std::reference_wrapper`` via ``std::ref()``/``std::cref()``. + a formatting function. **Example**:: fmt::dynamic_format_arg_store store; - char str[] = "1234567890"; - store.push_back(std::cref(str)); - int a1_val{42}; - auto a1 = fmt::arg("a1_", a1_val); - store.push_back(std::cref(a1)); - - // Changing str affects the output but only for string and custom types. - str[0] = 'X'; - - std::string result = fmt::vformat("{} and {a1_}"); - assert(result == "X234567890 and 42"); + char band[] = "Rolling Stones"; + store.push_back(std::cref(band)); + band[9] = 'c'; // Changing str affects the output. + std::string result = fmt::vformat("{}", store); + // result == "Rolling Scones" \endrst */ template void push_back(std::reference_wrapper arg) { static_assert( - detail::is_named_arg::type>::value || - need_copy::value, + need_copy::value, "objects of built-in types and string views are always copied"); emplace_arg(arg.get()); } @@ -198,7 +190,7 @@ class dynamic_format_arg_store /** Adds named argument into the dynamic store for later passing to a formatting function. ``std::reference_wrapper`` is supported to avoid copying of the - argument. + argument. The name is always stored by reference. */ template void push_back(const detail::named_arg& arg) { diff --git a/include/fmt/core.h b/include/fmt/core.h index 68cc7964..d0e06e26 100644 --- a/include/fmt/core.h +++ b/include/fmt/core.h @@ -1619,8 +1619,9 @@ inline auto make_args_checked(const S& format_str, /** \rst - Returns a named argument to be used in a formatting function. It should only - be used in a call to a formatting function. + Returns a named argument to be used in a formatting function. + It should only be used in a call to a formatting function or + `dynamic_format_arg_store::push_back`. **Example**:: diff --git a/test/core-test.cc b/test/core-test.cc index 5da58a60..b24d6635 100644 --- a/test/core-test.cc +++ b/test/core-test.cc @@ -469,24 +469,10 @@ TEST(FormatDynArgsTest, NamedStrings) { TEST(FormatDynArgsTest, NamedArgByRef) { fmt::dynamic_format_arg_store store; - - // Note: fmt::arg() constructs an object which holds a reference - // to its value. It's not an aggregate, so it doesn't extend the - // reference lifetime. As a result, it's a very bad idea passing temporary - // as a named argument value. Only GCC with optimization level >0 - // complains about this. - // - // A real life usecase is when you have both name and value alive - // guarantee their lifetime and thus don't want them to be copied into - // storages. - int a1_val{42}; - auto a1 = fmt::arg("a1_", a1_val); - store.push_back("abc"); - store.push_back(1.5f); - store.push_back(std::cref(a1)); - - std::string result = fmt::vformat("{a1_} and {} and {} and {}", store); - EXPECT_EQ("42 and abc and 1.5 and 42", result); + char band[] = "Rolling Stones"; + store.push_back(fmt::arg("band", std::cref(band))); + band[9] = 'c'; // Changing str affects the output. + EXPECT_EQ(fmt::vformat("{band}", store), "Rolling Scones"); } TEST(FormatDynArgsTest, NamedCustomFormat) {