[英]How do I print out the arguments of a function using a variadic template?
这个例子使用了一个通用的可变参数模板和函数。 我想打印出传递给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
这实际上是我第一次使用可变参数函数,我并不完全了解如何很好地使用它们。
我也不明白为什么这不起作用以及我能做些什么来帮助它。
由于这个问题很普遍,而且在 C++17 中你可以做得更好,我想给出两种方法。
使用折叠表达式,这可能很简单
#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
(见在线直播)
在if constexpr
的帮助下,现在我们可以避免向递归可变参数模板函数提供 base case/0-argument case。 这是因为编译器在编译时丢弃了if constexpr
中的 false 语句。
#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
(见在线直播)
你去吧。 您的代码中有几个错误,您可以在下面的行之间看到注释:
#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...);
}
你无限递归。 每次都需要从包中删除一个元素:
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.
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.