C++ 可变模板和类型推断问题

C++ 可变模板和类型推断问题,c++,c++11,type-conversion,variadic-templates,C++,C++11,Type Conversion,Variadic Templates,在问题15中,我被结果难住了 #include <iostream> template<typename T> void P(T x) { std::cout << x; } void foo(char a) { // foo 1 P(3); P(a); } template <typename... A> // foo 2 void foo(int a, A... args) { foo(args...);

在问题15中,我被结果难住了

#include <iostream>

template<typename T> void P(T x) { std::cout << x; }

void foo(char a) {  // foo 1
    P(3);
    P(a);
}

template <typename... A>  // foo 2
void foo(int a, A... args) {
    foo(args...);
    P(a);
}

template <typename... A>
void foo(char a, A... args) { // foo 3
    P(a);
    foo(args...);
}

int main()
{
    foo('1','2',48,'4','5');
}
#包括

模板空隙P(tx){std::cout
foo 2
无法调用
foo 3
,因为
foo 3
不在
foo 2
foo 2
的范围内,因为
foo 3
不在
foo 2
的范围内,这看起来是声明的顺序。如果您提前声明相关的重载o如果foo高于foo 2,则您将看到预期的结果,即将其置于foo 2之上:

template <typename... A>
void foo(char a, A... args);
模板
void foo(字符a,a…args);
本标准的相关部分见3.4.1.4:

在全局范围内使用的名称,不在任何函数、类或 用户声明的命名空间,应在全局 范围

在14.6.4.1从属名称解析中:

在解析依赖名称时,将使用以下来源的名称: 考虑到:

-在定义点可见的声明 模板的名称

-来自与 来自实例化上下文的函数参数的类型 (14.6.4.1)和定义上下文


由于
args
是一种依赖类型,名称解析仅考虑作为模板定义点可见的名称。
foo3
未在此点声明,因此不能在重载解析中考虑。基于此,Visual Studio允许使用
foo3

似乎是错误的这是声明的顺序。如果您将foo的相关重载声明在foo 2之上,那么您将看到您预期的结果,即将其置于foo 2之上:

template <typename... A>
void foo(char a, A... args);
模板
void foo(字符a,a…args);
本标准的相关部分见3.4.1.4:

在全局范围内使用的名称,不在任何函数、类或 用户声明的命名空间,应在全局 范围

在14.6.4.1从属名称解析中:

在解析依赖名称时,将使用以下来源的名称: 考虑到:

-在定义点可见的声明 模板的名称

-来自与 来自实例化上下文的函数参数的类型 (14.6.4.1)和定义上下文


由于
args
是一种依赖类型,名称解析只考虑作为模板定义点可见的名称。
foo3
未在此点声明,因此不能在重载解析中考虑。根据st标准,第3.3节,这正是“范围”。这是Visual Studio中的一个bug?是的,Visual Studio编译器以不符合标准的方式实现模板。根据标准,第3.3节,这正是“范围”是的,Visual Studio编译器以不符合标准的方式实现模板。