可变参数模板在以下情况下如何工作?

时间:2017-03-13 19:58:30

标签: c++ c++11

http://coliru.stacked-crooked.com/a/5d16c7e740a31a02

#include <iostream>
template<typename T> void P(T x) { std::cout << x; }
void foo(char a) {
    P(3);
    P(a);
}
template <typename... A>
void foo(int a, A... args) {
    foo(args...);
    P(a);
}
template <typename... A>
void foo(char a, A... args) {
    P(a);
    foo(args...);
}
int main()
{
    foo('1', '2', 48, '4', '5');
}

//1243548        My result (VS2015)
//12355248       correct result (clang, gcc)

&#34;如何纠正&#34;结果生成了吗?

1 个答案:

答案 0 :(得分:1)

这里的诀窍是int的{​​{1}}重载不知道foo重载,因为它还没有被看到,因此该级别的调用变为递归本身:

char

拨打template <typename... A> void foo(int a, A... args) { /* only ever calls itself and above*/}

如果 foo(48, '4', '5')被解释为foo(int a, A...) ,那么

将会追加chars的其他来电!

因此,您将按预期获得初始int,但之后您只会为字符打印ASCII值,因此您将获得12的值52'4'的值53。 Clang和gcc是正确的;您的Visual Studio版本正在打印错误的值。 (I was able to reproduce with VC 19.00.23506

这是一个呼叫追踪(instrumented with some help from C++17):

'5'

现在,如果我们移动你的代码以便我们转发声明我们的模板(这总是一个好习惯),你就会得到你想要的行为:

Called foo(char a, A... args) with 1,2,48,4,5
Called P(T) with 1
Called foo(char a, A... args) with 2,48,4,5
Called P(T) with 2
Called foo(int a, A... args) with 48,4,5
Called foo(int a, A... args) with 52,5
Called foo(char a) with 5
Called P(T) with 3
Called P(T) with 5
Called P(T) with 52
Called P(T) with 48

然后,您将获得所需的输出。这是该版本(demo)的堆栈跟踪:

template<typename T> 
void P(T x);

template <typename... A>
void foo(int a, A... args);

template <typename... A>
void foo(char a, A... args);

// actual definitions below...