I have a function with a parameter pack, I pass this pack to the fmt::format
function, and I want to create a formatStr
according to the args count, meaning add "{}#" for each passed argument.
I can do it using iterating, but is it possible to do this with one line solution? How to do it gracefully?
template <typename... Args>
void formatArgs( Args&&...args)
{
const auto size = sizeof...(Args);
std::string formatStr = ...// "{}#{}#{}..." - {}# should depend on args count
/*
std::ostringstream formatStr;
for (const auto& p : { args... })
formatStr << {}#";
*/
auto res = fmt::format(formatStr.c_str(), args...);
...
}
CodePudding user response:
An ugly fold expression would work. It's only redeeming quality is that it's just one line, and in C 20 it should be a constexpr, so in C 20 this'll wind up to be a single std::string
constructor call:
#include <string>
#include <iostream>
template<typename ...Args>
std::string string_from_args(Args && ...args)
{
return std::string{ ((args, std::string{"%s#"}) ...) };
}
int main()
{
std::cout << string_from_args(1, 2, 3, 4) << "\n";
return 0;
}
CodePudding user response:
If you want to create a string with all the arguments I suggest you use an std::ostringstream
to create the string directly instead of going through std::format
or similar.
How to create the string differs between version of C . Before C 17 and pre-fold you can use overloading of functions to handle the argument packs:
// Handle single-argument string construction
template<typename Arg>
std::string string_from_args(Arg&& arg)
{
return (std::ostringstream() << arg).str();
}
// Handle multiple-argument string construction
template<typename First, typename ...Rest>
std::string string_from_args(First&& first, Rest&& ...rest)
{
return (std::ostringstream() << string_from_args(first) << '#' << string_from_args(rest...)).str();
}
Then with fold-expressions introduced in C 17:
template<typename ...Args>
std::string string_from_args(Args&& ...args)
{
char const* separator = "";
std::ostringstream os;
(((os << separator << args), separator = "#"), ...);
return os.str();
}
With a simple main
function
int main()
{
std::cout << string_from_args(123, 456.789, "foo", 'b');
}
both variants should construct and print the string
123#456.789#foo#b