无法理解 C++ 中的可变参数模板
can't understand variadic templates in c++
我在阅读可变参数模板时遇到了这个例子。书中提到要结束递归过程,使用函数print()
。实在看不懂它的用途。为什么作者要用这个空的print()
函数?
void print () // can't get why this function is used
{
}
template <typename T, typename... Types>
void print (const T& firstArg, const Types&... args)
{
std::cout << firstArg << std::endl; // print first argument
print(args...); // call print() for remaining arguments
}
它是递归的,因为每次调用都会减少模板的可变参数部分,例如,递归调用看起来像这样
print(1, 2, 3, 4, 5) // firstArg == 1
// ...args == 2,3,4,5
print(2, 3, 4, 5) // firstArg == 2
// ...args == 3,4,5
print(3, 4, 5) // firstArg == 3
// ...args == 4,5
print(4, 5) // firstArg == 4
// ...args == 5
print(5) // firstArg == 5
// ...args == {}
print()
当可变参数列表为空时,print()
是必要的基本情况。
可变参数表达式可以捕获 0 个参数或更多。
以调用 print(1)
为例。然后 T
捕获 int
和 Types = {}
- 它不捕获任何参数。因此调用 print(args...);
扩展为 print();
,这就是为什么你需要一个基本案例。
你根本不需要递归。我总是在我的代码中使用以下 debuglog
函数(根据您的需要进行修改):
template<typename F, typename ... Args>
void
print(const F& first, const Args&... args) // At least one argument
{
std::cout << first << std::endl;
int sink[] =
{ 0, ((void)(std::cout << args << std::endl), 0)... };
(void) sink;
}
因为这个可变参数函数至少接受一个参数,所以您现在可以随意使用 print(void)
。
考虑使用单个参数调用模板函数。
print(1);
firstArg
将绑定到 1
(T = int
),而 Types...
将不绑定任何内容。可变参数包是 零 或更多参数。
因此,在这个调用中:
print(args...);
args...
是一个空参数包。所以它扩展为:
print();
由于您的函数模板匹配任何使用 一个 或多个参数的 print 调用,因此您需要一个单独的函数来处理零参数。在这种情况下,这是微不足道的功能:
void print () { }
假设以下代码:
int a, b, c;
print(a, b, c);
编译器将隐式创建以下代码:
print(const int& firstArg)
{
std::cout << firstArg << std::endl; // print first argument
print(); // call print() for remaining arguments
}
print(const int& firstArg, const int& arg2)
{
std::cout << firstArg << std::endl; // print first argument
print(arg2); // call print() for remaining arguments
}
print(const int& firstArg, const int& arg2, const int& arg3)
{
std::cout << firstArg << std::endl; // print first argument
print(arg2, arg3); // call print() for remaining arguments
}
正如您在只有一个参数的版本中看到的那样,编译器将调用一个 "print" 方法而不带参数。由于可变打印函数总是需要至少一个参数,因此这将不匹配...
我在阅读可变参数模板时遇到了这个例子。书中提到要结束递归过程,使用函数print()
。实在看不懂它的用途。为什么作者要用这个空的print()
函数?
void print () // can't get why this function is used
{
}
template <typename T, typename... Types>
void print (const T& firstArg, const Types&... args)
{
std::cout << firstArg << std::endl; // print first argument
print(args...); // call print() for remaining arguments
}
它是递归的,因为每次调用都会减少模板的可变参数部分,例如,递归调用看起来像这样
print(1, 2, 3, 4, 5) // firstArg == 1
// ...args == 2,3,4,5
print(2, 3, 4, 5) // firstArg == 2
// ...args == 3,4,5
print(3, 4, 5) // firstArg == 3
// ...args == 4,5
print(4, 5) // firstArg == 4
// ...args == 5
print(5) // firstArg == 5
// ...args == {}
print()
当可变参数列表为空时,print()
是必要的基本情况。
可变参数表达式可以捕获 0 个参数或更多。
以调用 print(1)
为例。然后 T
捕获 int
和 Types = {}
- 它不捕获任何参数。因此调用 print(args...);
扩展为 print();
,这就是为什么你需要一个基本案例。
你根本不需要递归。我总是在我的代码中使用以下 debuglog
函数(根据您的需要进行修改):
template<typename F, typename ... Args>
void
print(const F& first, const Args&... args) // At least one argument
{
std::cout << first << std::endl;
int sink[] =
{ 0, ((void)(std::cout << args << std::endl), 0)... };
(void) sink;
}
因为这个可变参数函数至少接受一个参数,所以您现在可以随意使用 print(void)
。
考虑使用单个参数调用模板函数。
print(1);
firstArg
将绑定到 1
(T = int
),而 Types...
将不绑定任何内容。可变参数包是 零 或更多参数。
因此,在这个调用中:
print(args...);
args...
是一个空参数包。所以它扩展为:
print();
由于您的函数模板匹配任何使用 一个 或多个参数的 print 调用,因此您需要一个单独的函数来处理零参数。在这种情况下,这是微不足道的功能:
void print () { }
假设以下代码:
int a, b, c;
print(a, b, c);
编译器将隐式创建以下代码:
print(const int& firstArg)
{
std::cout << firstArg << std::endl; // print first argument
print(); // call print() for remaining arguments
}
print(const int& firstArg, const int& arg2)
{
std::cout << firstArg << std::endl; // print first argument
print(arg2); // call print() for remaining arguments
}
print(const int& firstArg, const int& arg2, const int& arg3)
{
std::cout << firstArg << std::endl; // print first argument
print(arg2, arg3); // call print() for remaining arguments
}
正如您在只有一个参数的版本中看到的那样,编译器将调用一个 "print" 方法而不带参数。由于可变打印函数总是需要至少一个参数,因此这将不匹配...