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

时间:2012-09-09 20:21:10

标签: c++ templates

此示例使用常见的可变参数模板和函数。我想打印出传递给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);

}

但我收到以下错误:

  

编译完成但有错误:
  source.cpp:实例化'void f(T ...) [with T = {int, int, int, int, int}]':
  source.cpp:16:20:从这里要求
  source.cpp:10:4:错误:没有匹配函数来调用'print(int&, int&, int&, int&, int&)'   source.cpp:10:4:注意:候选人是:
  source.cpp:4:6:注意:template<class T> void print(T)
  source.cpp:4:6:注意:模板参数扣除/替换失败:   source.cpp:10:4:注意:候选人需要1个参数,5个提供

这实际上是我第一次使用可变参数函数而我并不完全理解如何使用它们。我也不明白为什么这不起作用,我能做些什么来帮助它。

3 个答案:

答案 0 :(得分:4)

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

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

请注意,在这里使用rvalue refs是没有意义的。你没有将参数存储在任何地方,所以只需通过const引用传递它们就可以了。这样你也可以避免使用std::forward来保持(无用)完美转发。

因此,您可以按如下方式重写f

template <typename T, typename...Ts>
void f(const T &first, const Ts&... rest) {
    print(first);
    f(rest...);
}

答案 1 :(得分:4)

更新!

由于问题很普遍,在C ++ 17中您可以做得更好,所以我想给出两种方法。

解决方案-我

使用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,现在我们可以避免为递归variadic template function提供基本情况/ 0参数的情况。这是因为编译器在编译时会丢弃if 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 :(得分:1)

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

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.