template<class Msg, class... Args>
std::wstring descf(Msg, Args&&... args) {
std::wostringstream woss;
owss << Msg << ". " << ... << " " << args << ": '" << args << "' ";//not legal at all
//or
owss << Msg << ". " << args[0] << ": '" << args[1] << "' " << args[2] << ": '" << args[3] << "' "; //... pseudo code, and so on...
}
代わりにペアのリストなどを使用できることはわかっていますが、関数の構文を次のように維持しながら、これを行う方法に興味があります。
const auto formatted = descf(L"message", "arg1", arg1, "arg2", arg2);
折りたたみ式が使える!それは最も美しい*ではありませんが、提示されているすべての非折りたたみソリューションよりも短いです:
template<class T, class ... Args>
std::wstring descf(T msg, Args&&... args) {
std::wostringstream owss;
owss << msg << ". ";
std::array<const char*, 2> tokens{": '", "' "};
int alternate = 0;
((owss << args << tokens[alternate], alternate = 1 - alternate), ...);
return owss.str();
}
サンプル出力を使ったデモ: https://godbolt.org/z/Gs8d2x
コンマ演算子のフォールドを実行します。各オペランドは、1つのargs
と代替トークンの出力に加えて、トークンインデックスを切り替えます(後者の2つは別のコンマ演算子と組み合わされます)。
*折りたたみ式(およびカンマ演算子)をよく知っている読者には、これはおそらく「最良の」コードですが、他のすべての人にとってはまったく意味不明なので、コードベースにこれを適用するかどうかを自分で判断してください。
これは、次のパターンに従ういくつかのヘルパー関数で簡単です。
void helper() {}
template <class T1, class T2, class ... T>
void helper(T1 t1, T2 t2, T ... t)
{
do_single_pair(t1, t2);
helper(t...);
}
これはフォールド式ではありませんが、最終的な結果は同じです。
インデックスと三項演算子を使って試すことができると思います。
次のようなもの
template <typename ... Args>
std::wstring descf (std::wstring const & Msg, Args && ... args)
{
std::wostringstream woss;
int i = 0;
((woss << Msg << ". "), ... ,(woss << args << (++i & 1 ? ": '" : "' ")));
return woss.str();
}
次のコードでうまくいくはずです。パラメータパックは、初期化リストで展開されます。
#include <string>
#include <iostream>
#include <sstream>
#include <vector>
template <typename...Args>
std::string descf(std::string msg, Args &&... args)
{
auto argumentsVector = std::vector<std::string>{args...};
std::stringstream ss;
ss << msg << ". ";
for (auto i = std::size_t{0}; i < argumentsVector.size() - 1; ++i)
ss << argumentsVector[i] << ": '" << argumentsVector[i+1] << "' ";
auto result = ss.str();
if (!argumentsVector.empty())
result.pop_back();
return result;
}
int main()
{
std::cout << descf("message", "arg1", "1", "arg2", "2") << std::endl;
}
std::index_sequence
:
template <class Msg, class... Pairs>
std::wstring descf_pair(const Msg& msg, const Pairs&... pairs)
{
std::wstringstream woss;
woss << msg << ". ";
auto sep = L"";
((woss << sep << std::get<0>(pairs) << L": '"
<< std::get<1>(pairs) << L"'", sep = L" "), ...);
return woss.str();
}
template <class Msg, std::size_t... Is, class Tuple>
decltype(auto) descf_impl(const Msg& msg, std::index_sequence<Is...>, Tuple&& t)
{
return descf_pair(msg, std::tie(std::get<2 * Is>(t), std::get<2 * Is + 1>(t))...);
}
template <class Msg, typename ... Ts>
std::wstring descf(const Msg& msg, const Ts&... ts)
{
static_assert(sizeof...(Ts) % 2 == 0);
return descf_impl(msg,
std::make_index_sequence<sizeof...(Ts) / 2>(),
std::tie(ts...));
}