C++ 如何对参数包进行分组或成对折叠?

C++ 如何对参数包进行分组或成对折叠?,c++,c++17,variadic-templates,fold-expression,C++,C++17,Variadic Templates,Fold Expression,使用遵循以下模式的两个助手函数很容易做到这一点 const auto formatted = descf(L"message", "arg1", arg1, "arg2", arg2); void helper(){} 模板 空洞辅助物(T1,T2,T…T) { do_单_对(t1,t2); 助手(t…); } 这不是一个折叠表达式,但最终结果是相同的。下面的代码应该可以做到这一点。参数包在初始值设定项列表中展开 void helper() {} template <class T1

使用遵循以下模式的两个助手函数很容易做到这一点

const auto formatted = descf(L"message", "arg1", arg1, "arg2", arg2);
void helper(){}
模板
空洞辅助物(T1,T2,T…T)
{
do_单_对(t1,t2);
助手(t…);
}

这不是一个折叠表达式,但最终结果是相同的。

下面的代码应该可以做到这一点。参数包在初始值设定项列表中展开

void helper() {}

template <class T1, class T2, class ... T>
void helper(T1 t1, T2 t2, T ... t)
{
     do_single_pair(t1, t2);
     helper(t...);
}
#包括
#包括
#包括
#包括
模板
std::string descf(std::string msg,Args&&…Args)
{
自动参数vector=std::vector{args…};
std::stringstream-ss;

ss您可以使用折叠表达式!它不是最漂亮的*,但比所有非折叠解决方案都要短:

#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::wstring descf(T msg,Args&…Args){
std::wostringowss;

我想你可以尝试使用索引和三元运算符

如下

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();
}
模板
std::wstring descf(std::wstring const&Msg,Args&……Args)
{
std::wostringstream-woss;
int i=0;

((woss带有
std::index_序列

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();
 }
模板
std::wstring descf_对(常量消息和消息、常量对和…对)
{
std::wstringstream woss;

woss这要求所有的
args
都可以转换为
std::string
s.@walnut,这是正确的。如果这不是一个要求,那么您必须生成折叠表达式/递归模板递归深度是否与折叠表达式不同?或者是same@darunefold-ex没有固有的递归按…折叠表达式只是形式上扩展到某个表达式(在变量模板的特定实例化中)。我想这也可以用于布尔运算(如果只需要配对)ala.:b^=true;然后可能是十进制运算符(b?:“,:”)@darune当然,还有其他方式来表达这种交替。我决定将输出/交替逻辑与实际的标记值分开,数组很好地完成了这一点。我不喜欢索引时从
bool
int
的隐式转换,所以我使用了实际的
int
来切换状态。以及pre-vs-postfix
++
需要额外的思维周期来验证(至少对我来说),而单独的
1-
不会被误读。简言之,我尽量让它可读,但这当然取决于个人品味(或适用的风格指南).max66将其压缩得更多。使用
std::array
而不是本机数组似乎是一个毫无意义的复杂问题。@重复数据消除程序我强烈反对,因为我发现
std::array
const char**
可读性要大得多。但是,这也是我在一些非常模糊的语法的可读性方面的最佳尝试,您可以使用它在你自己的代码中,我所能做的就是给你一个我认为可读的数据点。@ Max LangHOF的优点是(容易)扩展到更多的分隔符。@去重复器我不明白你指的是什么?你能解释吗?@ De复复器-不清楚“扩展到更多的分隔符”是什么意思?“……无论如何……这个解决方案与公认的解决方案非常相似;我不认为它或多或少具有可扩展性。我认为这稍微轻了一点(一点!也许编译器以同样的方式优化),因为避免使用
std::array
(无论如何,这是一个轻类),但是(因此我认为公认的答案更可取)它的可读性较差。
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();
 }
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...));
}