可变参数模板未在 MSVC 中编译?

Variadic templates not compiling in MSVC?

本文关键字:MSVC 编译 变参 参数      更新时间:2023-10-16

正在尝试编译以下代码片段: 此代码显然使用了 C++11 功能,并在 C++ 编程语言书籍 §3.4.4 中进行了描述

template<typename T>
void g(T x)
{
std::cout << x << " ";
}
template<typename T, typename... Tail>
void f(T head, Tail... tail) {
g(head); // do something to head
f(tail...); // tr y again with tail
}
void f() {}
int main()
{
f(1, "Lol", 5);
getchar();
}

VS17 输出 :

C2672 'f':未找到匹配的重载函数 行:21

'void f(T,Tail...(':期望 2 个参数 - 0 提供 行:19

有什么想法吗?

这里有三件事不正确。

  1. tail参数阴影模板名称tail
  2. 没有可行的函数来处理递归调用的基本情况f()
  3. f()必须在其他f(...)之前定义,因为高级函数查找不会在此类递归函数中进行。

解决 方案

将参数tail的名称更改为其他类似

template<typename T, typename... tail>
void f(T head, tail... ftail) { //tail here was shadowing actual template name tail so changed to ftail
g(head); // do something to head
f(ftail...); // try again with tail
}

当您对f()进行递归调用时,有时会没有向f(..)传递任何值,因为每次递归调用都会将传递的参数数减少 1。

假设你从f(1, "Lol", 2)开始,在内部进行递归调用是为了f("Lol", 2)这个轮次调用f(2)调用f(),但你的函数f至少需要 1 个参数。因此错误

要解决这个问题,只需重载基本情况的f,没有像这样的参数

void f(){
//last recursive call made
}

这是完整的代码

#include<iostream>
template<typename T>
void g(T x)
{
std::cout << x << " ";
}
void f(){ }
template<typename T, typename... tail>
void f(T head, tail... ftail) {
g(head); // do something to head
f(ftail...); // try again with tail
}
int main()
{
f(1, "Lol", 5);
getchar();
}

首先是MCVE:

template<typename T, typename... Tail>
void f(T head, Tail... tail) {
f(tail...); // tr y again with tail
}
f(1, 2, 3);

现在实例化:

f<int, int, int>(1, 2, 3);

编译为:

template<T = int, Tail...={int,int}>
void f(int head, int tail0, int tail1) {
f(tail0, tail1); // tr y again with tail
}

递归调用是:

f<int,int>(tail0, tail1); // tr y again with tail

编译为:

template<T = int, Tail...={int}>
void f(int head, int tail0) {
f(tail0); // tr y again with tail
}

递归调用解析为:

f<int>(tail0); // tr y again with tail

编译为:

template<T = int, Tail...={}>
void f(int head) {
f(); // tr y again with tail
}

在这里,我们尝试称f().

没有有效的调用f()可见,因此会出现错误。

调用f()下的void f() {}在这里没有帮助,因为在模板中,查找是在f()可见之前完成的。

如果要以简单的方式解决此问题,可以在f模板上方添加inline void f(){}

更复杂的方法?

template<class...Ts>
void f(Ts...ts) {
using discard=int[];
(void)discard{ 0, ( void(
g(ts)
),0)...};
}

这也消除了递归。 或者在 c++17 中:

template<class...Ts>
void f(Ts...ts) {
( (void)(g(ts)), ... );
}

这也更快编译,因为它创建的符号更少(更短(。