How do I print out the arguments of a function using a variadic template?

后端 未结 3 1619
灰色年华
灰色年华 2020-12-12 01:17

This example uses a common variadic template and function. I want to print out the arguments passed to f:

#include 

template <         


        
相关标签:
3条回答
  • 2020-12-12 01:18

    You're recursing infinitely. You need to remove one element from the pack each time:

    void print() { }                            // 0-argument overload
    
    template <typename Head, typename ...Tail>
    void print(Head const & h, Tail const &... t)         // 1+-argument overload
    {
        std::cout << h;
        print(t...);
    }
    

    You can wrap your function call up with the printing:

    template <typename ...Args>
    void print_and_f(Args &&... args)
    {
        print(args...);
        f(std::forward<Args>(args)...);
    }
    

    Usage:

    print_and_f(1, 2, 3);  // calls "f(1, 2, 3)" eventually.
    
    0 讨论(0)
  • 2020-12-12 01:19

    There you go. You had several mistakes in your code, you can see the comments between the lines below:

    #include <iostream>
    
    template <typename T>
    void print(T t) {
       std::cout << t << std::endl;
    }
    
    // Base case, no args
    void f() {}
    
    // Split the parameter pack.
    // We want the first argument, so we can print it.
    // And the rest so we can forward it to the next call to f
    template <typename T, typename...Ts>
    void f(T &&first, Ts&&... rest) {
        // print it
        print(std::forward<T>(first));
        // Forward the rest.
        f(std::forward<Ts>(rest)...);
    }
    
    int main() {
        f(2, 1, 4, 3, 5);
    }
    

    Note that using rvalue refs here makes no sense. You're not storing the parameters anywhere, so simply passing them by const reference should do it. That way you'd also avoid using std::forward just to keep the (useless) perfect forwarding.

    Therefore, you could rewrite f as follows:

    template <typename T, typename...Ts>
    void f(const T &first, const Ts&... rest) {
        print(first);
        f(rest...);
    }
    
    0 讨论(0)
  • 2020-12-12 01:27

    c++17 Updates!

    Since the question is general and in C++17 you can do it better, I would like to give two approaches.

    Solution - I

    Using fold expression, this could be simply

    #include <iostream>
    #include <utility>  // std::forward
    
    template<typename ...Args>
    constexpr void print(Args&&... args) noexcept
    {
       ((std::cout << std::forward<Args>(args) << " "), ...);
    }
    
    int main()
    {
       print("foo", 10, 20.8, 'c', 4.04f);
    }
    

    output:

    foo 10 20.8 c 4.04 
    

    (See Live Online)


    Solution - II

    With the help of if constexpr, now we can avoid providing base case/ 0-argument case to recursive variadic template function. This is because the compiler discards the false statement in the if constexpr at compile time.

    #include <iostream>
    #include <utility>  // std::forward
    
    template <typename T, typename...Ts>
    constexpr void print(T&& first, Ts&&... rest) noexcept
    {
       if constexpr (sizeof...(Ts) == 0)
       {
          std::cout << first;               // for only 1-arguments
       }
       else
       {
          std::cout << first << " ";        // print the 1 argument
          print(std::forward<Ts>(rest)...); // pass the rest further
       }
    }
    
    int main()
    {
       print("foo", 10, 20.8, 'c', 4.04f);
    }
    

    output

    foo 10 20.8 c 4.04
    

    (See Live Online)

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