代码之家  ›  专栏  ›  技术社区  ›  David G

如何使用可变模板打印函数的参数?

  •  2
  • David G  · 技术社区  · 12 年前

    这个例子使用了一个通用的可变模板和函数。我想把传递给的论点打印出来 f 以下为:

    #include <iostream>
    
    template <typename T>
    void print(T t) 
    {
        std::cout << t << std::endl;
    }
    
    template <typename...T>
    void f(T &&...args) 
    {
        print(args...);
        f(args...);
    }
    
    int main() 
    {
        f(2, 1, 4, 3, 5);
    }
    

    但我得到了以下错误:

    Compilation finished with errors:<br>
    source.cpp: In instantiation of '`void f(T ...)` [with `T = {int, int, int, int, int}`]':<br>
    source.cpp:16:20: required from here <br>
    source.cpp:10:4: error: no matching function for call to '`print(int&, int&, int&, int&, int&)`'<br>
    source.cpp:10:4: note: candidate is:<br>
    source.cpp:4:6: note: `template<class T> void print(T)`<br>
    source.cpp:4:6: note: template argument deduction/substitution failed: 
    source.cpp:10:4: note: candidate expects 1 argument, 5 provided
    

    这实际上是我第一次使用变差函数,我并不完全理解如何很好地使用它们。

    我也不明白为什么这不起作用,以及我能做些什么来帮助它。

    3 回复  |  直到 4 年前
        1
  •  6
  •   JeJo    4 年前

    更新!

    由于这个问题很一般,而且在C++17中你可以做得更好,我想给出两种方法。

    解决方案-I

    使用 fold expression ,这可以简单地

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

    输出:

    foo 10 20.8 c 4.04 
    

    ( See Live Online )


    解决方案-II

    在的帮助下 if constexpr ,现在我们可以避免为递归提供基本情况/0-参数情况 variadic template function 。这是因为编译器在 如果constexpr 在编译时。

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

    输出

    foo 10 20.8 c 4.04
    

    ( See Live Online )

        2
  •  4
  •   mfontanini    12 年前

    给你。你的代码中有几个错误,你可以看到下面几行之间的注释:

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

    请注意,在这里使用右值参考毫无意义。您没有将参数存储在任何地方,所以只需通过const引用传递它们就可以了 std::forward 只是为了保持(无用的)完美转发。

    因此,您可以重写 f 如下所示:

    template <typename T, typename...Ts>
    void f(const T &first, const Ts&... rest) {
        print(first);
        f(rest...);
    }
    
        3
  •  1
  •   Kerrek SB    12 年前

    你在无限递归。每次都需要从包中删除一个元素:

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

    您可以使用打印来结束函数调用:

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

    用法:

    print_and_f(1, 2, 3);  // calls "f(1, 2, 3)" eventually.