Variadic模板没有编译MSVC编译器?

问题描述 投票:1回答:2

尝试编译以下代码片段:此代码显然使用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提供Line:19

有任何想法吗 ?

c++ visual-studio c++11 templates
2个回答
1
投票

这里有三件事不正确。

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

1
投票

首先是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()调用可见,因此您收到错误消息。

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

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

更复杂的方式?

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

这也消除了递归。或者在

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

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

© www.soinside.com 2019 - 2024. All rights reserved.