Reputation: 523
I'm playing with the great fmt C++ library to format strings more gracefully.
And I'd like to pass a non-variable arguments list to fmt::format
. It could be a std::vector
, or std::string
, or whatever, but it will always match the format string.
So fmt::format
works like:
std::string message = fmt::format("The answer is {} so don't {}", "42", "PANIC!");
But what I'd like is something like:
std::vector<std::string> arr;
arr.push_back("42");
arr.push_back("PANIC!");
std::string message = fmt::format("The answer is {} so don't {}", arr);
Is there a way / workaround to do so?
Upvotes: 5
Views: 6168
Reputation: 31
In the current version (8.1.1) the following is possible;
fmt::dynamic_format_arg_store<fmt::format_context> ds;
ds.push_back(42);
ds.push_back("PANIC");
std::string msg = fmt::vformat("The answer is {} so don't {}", ds);
Upvotes: 3
Reputation: 303186
You can build up the arguments to vformat
on your own from your vector
. This seems to work:
std::string format_vector(std::string_view format,
std::vector<std::string> const& args)
{
using ctx = fmt::format_context;
std::vector<fmt::basic_format_arg<ctx>> fmt_args;
for (auto const& a : args) {
fmt_args.push_back(
fmt::internal::make_arg<ctx>(a));
}
return fmt::vformat(format,
fmt::basic_format_args<ctx>(
fmt_args.data(), fmt_args.size()));
}
std::vector<std::string> args = {"42", "PANIC!"};
std::string message = format_vector("The answer is {} so don't {}", args);
Upvotes: 9
Reputation: 217478
Add an extra layer, something like:
template <std::size_t ... Is>
std::string my_format(const std::string& format,
const std::vector<std::string>& v,
std::index_sequence<Is...>)
{
return fmt::format(format, v[Is]...);
}
template <std::size_t N>
std::string my_format(const std::string& format,
const std::vector<std::string>& v)
{
return my_format(format, v, std::make_index_sequence<N>());
}
Usage would be:
std::vector<std::string> arr = {"42", "PANIC!"};
my_format<2>("The answer is {} so don't {}", arr);
With operator ""_format
you might have the information about expected size at compile time
Upvotes: 4
Reputation: 72401
It doesn't look like this is possible without making changes to the fmt library. fmt::format
calls fmt::vformat
which takes a fmt::format_args
or fmt::wformat_args
object representing multiple arguments, but the only ways provided to create format_args
or wformat_args
objects are via another variadic function, which means the number and types of the arguments must be known at compile time.
So you could write a wrapper to unpack a std::tuple
or std::array
and pass its elements to fmt::format
, because the number and types of elements in those is known at compile time. But you can't do the same with a std::vector
, std::list
, etc., since the size of those containers can vary at runtime.
Upvotes: 1