使用折叠表达式在

时间:2017-03-28 12:49:45

标签: c++ variadic-templates c++17 fold-expression

C ++ 17折叠表达式的经典示例是打印所有参数:

template<typename ... Args>
void print(Args ... args)
{
    (cout << ... << args);
}

示例:

print("Hello", 12, 234.3, complex<float>{12.3f, 32.8f});

输出:

Hello12234.3(12.3,32.8)

我想在输出中添加换行符。但是,我找不到一个很好的方法来做到这一点,到目前为止我发现的最好:

template<typename ... Args>
void print(Args ... args)
{
    (cout << ... << ((std::ostringstream{} << args << "\n").str()));
}

然而,这不是零开销,因为它为每个参数构造了一个临时的ostringstream

以下版本不起作用:

(cout << ... << " " << args);

error: expression not permitted as operand of fold expression

(cout << ... << (" " << args));

error: invalid operands to binary expression 

我理解为什么最后两个版本不起作用。 使用折叠表达式是否有更优雅的解决方案?

2 个答案:

答案 0 :(得分:11)

更新:T.C.下面的评论提供了更好的解决方案:

template<typename ... Args>
void print(Args ... args)
{
    ((cout << args << '\n'), ...);
}

您可以在逗号运算符上使用 fold表达式

template<typename ... Args>
void print(Args ... args)
{
    ([](const auto& x){ cout << x << "\n"; }(args), ...);
}

用法:

int main()
{
    print("a", 1, 1000);
}
  

     

1

     

1000

(注意:这也会打印一个尾随换行符。)

说明:

  • [](const auto& x){ cout << x << "\n"; }是一个lambda,其x打印x'\n'

  • [](const auto& x){ cout << x << "\n"; }(args)立即使用args调用lambda。

  • ([](const auto& x){ cout << x << "\n"; }(args), ...)逗号运算符的折叠表达式,它以下列方式展开:

    // (pseudocode)
    [](const auto& x){ cout << x << "\n"; }(args<0>),
    [](const auto& x){ cout << x << "\n"; }(args<1>),
    [](const auto& x){ cout << x << "\n"; }(args<2>),
    // ...
    [](const auto& x){ cout << x << "\n"; }(args<N>)
    

答案 1 :(得分:6)

order by接受一个函数对象SELECT notification.type, notification.triggerer, notification.to_what, ANY_VALUE(user_data.name) AS name, ANY_VALUE(user_data.surname) AS surname, ANY_VALUE(user_data.avatarimage) AS avatarimage, COUNT(*) AS counter FROM notification INNER JOIN user_data ON notification.triggerer = user_data.owner WHERE notification.owner = "c6cecc891f6c4cc84cc0b62062578e52" AND isdelete=0 GROUP BY notification.triggerer, notification.type, notification.to_what ORDER BY notification.id DESC LIMIT 0,100 ,并返回一个新的函数对象。返回值在每个args上运行f。它在每个args上“重复”repeat

f

使用:

f

这使用折叠表达式,但只是间接表达。老实说,你可以用C ++ 14编写这个(只是template<class F> auto repeat( F&& f ) { return [f=std::forward<F>(f)](auto&&...args)mutable{ ( void(f(args)), ... ); }; } 的主体会更加丑陋)。

我们还可以编写一个与repeat ( [](auto&&x){ std::cout << x << "\n"; } ) ( args... ); 配合使用的流媒体“更内联”并直接使用折叠表达式:

repeat

然后我们像这样使用它:

<<

template<class F> struct ostreamer_t { F f; friend std::ostream& operator<<( std::ostream& os, ostreamer_t&& self ) { std::move(self).f(os); return os; } }; template<class F> ostreamer_t<F> ostreamer( F&& f ) { return {std::forward<F>(f)}; } 接受一个函数对象。它返回一个重载(std::cout << ... << ostreamer([&](auto&& os){ os << " " << args;})); 的对象,这样当你在左边传递一个ostream时,它会用ostream调用函数对象。

没有创建临时流。

Live examples