How can I create a format string using std functions (not the external fmt library), where the format arguments are contained within a std::vector<std::string>
.
Something like the following (but this example version doesn't compile):
std::string format(std::string fmt, const std::vector<std::string>& list) {
return std::vformat(fmt, std::make_format_args(list.begin(), list.end()));
}
How can I create a format string using std functions (not the external fmt library), where the format arguments are contained within a std::vector<std::string>
.
Something like the following (but this example version doesn't compile):
std::string format(std::string fmt, const std::vector<std::string>& list) {
return std::vformat(fmt, std::make_format_args(list.begin(), list.end()));
}
Share
Improve this question
edited Mar 30 at 23:43
David G
96.9k41 gold badges172 silver badges258 bronze badges
asked Mar 30 at 23:28
DessDess
2,68727 silver badges41 bronze badges
3
- The library is no longer external as of C++20. – PaulMcKenzie Commented Mar 30 at 23:53
- @PaulMcKenzie: I'm talking about the actual 'fmt' external library, not the C++ format facilities. I obviously showed that in the example code. – Dess Commented Mar 30 at 23:58
- You can't. If you can at least change to a container with compile-time size, you can do something like this: godbolt./z/earGYsWvT – Intelligent Shade of Blue Commented Mar 31 at 0:58
1 Answer
Reset to default 0I don't think what you are attempting is possible with standard formatting functions. std::format()
and friends utilize template parameter packs for their input arguments, and parameter packs can only be constructed at compile-time, not dynamically at runtime.
To do what you want, you will need to manually pull apart the fmt
string into replacement and non-replacement substrings, and then build up the output std::string
concatenation those substrings, making replacements as needed.
For example, if you have a fmt
string "{} {} my name is {}"
and a vector {"Hello", "World", "Dess"}
, then you would extract the following substrings and then concatenate them together:
"{}"
-> "Hello"
" "
"{}"
-> "World"
" my name is "
"{}"
-> "Dess"
However, note that prior to C++26, std::format()
requires a string literal for its fmt
parameter. So you can't use std::format()
in this case. C++26 will introduce std::runtime_format
so you can pass in a std::string
/std::string_view
constructed at runtime, but in the meantime, you will have to use std::vformat()
and std::make_format_args()
with single-argument replacements.
Try something like this:
std::string format(const std::string_view &fmt, const std::vector<std::string>& list) {
std::string result;
std::string::size_type start = 0, pos, end;
std::vector<std::string>::size_type idx = 0;
while ((pos = fmt.find('{', start)) != std::string::npos) {
if (pos > start) result += fmt.substr(start, pos-start);
if ((end = fmt.find('}', pos+1)) == std::string::npos) break;
++end;
result += std::vformat(fmt.substr(pos, end-pos), std::make_format_args(list.at(idx++)));
start = end;
}
if (start < fmt.size()) result += fmt.substr(start);
return result;
}
Live Demo
Obviously, you'll have to make this more robust to support the full syntax that the fmt
parameter supports, but this should give you an idea to start with.