Using fold expressions to print all variadic arguments with newlines inbetween

前端 未结 2 871
耶瑟儿~
耶瑟儿~ 2021-02-20 03:54

The classic example for C++17 fold expressions is printing all arguments:

template
void print(Args ... args)
{
    (cout << ... &l         


        
相关标签:
2条回答
  • 2021-02-20 04:18

    Update: T.C.'s comment below provided a better solution:

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

    You can use a fold expression over the comma operator:

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

    Usage:

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

    a

    1

    1000

    (Note: this prints a trailing newline as well.)

    • live wandbox example

    • assembly comparison on godbolt


    Explanation:

    • [](const auto& x){ cout << x << "\n"; } is a lambda that given x prints x and '\n'.

    • [](const auto& x){ cout << x << "\n"; }(args) immediately invokes the lambda with args.

    • ([](const auto& x){ cout << x << "\n"; }(args), ...) is a fold expression over the comma operator that expands in the following way:

      // (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>)
      
    0 讨论(0)
  • 2021-02-20 04:22

    repeat takes a function object f, and return a new function object. The return value runs f on each of its args. It "repeats" f on each of its args.

    template<class F>
    auto repeat( F&& f ) {
      return [f=std::forward<F>(f)](auto&&...args)mutable{
        ( void(f(args)), ... );
      };
    }
    

    Use:

    repeat
    ( [](auto&&x){ std::cout << x << "\n"; } )
    ( args... );
    

    This uses fold expressions, but only indirectly. And honestly, you could have written this in C++14 (just the body of repeat would be uglier).

    We could also write a streamer that works with << to do it "more inline" and use fold expressions directly:

    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)}; }
    

    then we use it like this:

    (std::cout << ... << ostreamer([&](auto&& os){ os << " " << args;}));
    

    ostreamer takes a function object. It returns an object that overloads << such that when you pass it an ostream on the left, it invokes the function object with the ostream.

    No temporary stream is created.

    Live examples.

    0 讨论(0)
提交回复
热议问题