c ++函数解析选择模板化版本而不是普通函数
c++ function resolution selects templated version over plain function
考虑以下代码:
#include <iostream>
template<typename T>
void f(T t)
{
(void)t;
std::cout << "templated f(T)\n";
}
template<typename T>
void entry(T t)
{
f(t);
}
void f(double d)
{
(void)d;
std::cout << "normal f(double)\n";
}
int main()
{
double d = 0.0;
entry(d);
return 0;
}
输出:
templated f(T)
我觉得这很奇怪,因为我认为普通函数会比任何模板版本都被选中。为什么会这样?
我在玩耍时注意到的另一件事是:如果我将普通函数 void f(double)
放在模板化的 void entry(T)
函数之前,代码将调用普通函数,基本上输出:
normal f(double)
因此我的另一个问题是:为什么顺序在这个特定示例中很重要?
f(double)
的重载在解析 entry(T)
模板时对编译器不可见。因此,在实例化 entry(T)
模板时,它不会参与重载决策。当涉及到在模板实例化上下文中解析重载时,这只是一个模糊的规则。为了考虑重载,它必须在解析模板定义之前已经在翻译单元中可见。
f
是从属名称,因为它依赖于类型为模板参数的 t
。相关名称的名称查找规则在 [temp.dep.res]/1:
中给出
In resolving dependent names, names from the following sources are considered:
- Declarations that are visible at the point of definition of the template.
- Declarations from namespaces associated with the types of the function arguments both from the
instantiation context (14.6.4.1) and from the definition context.
换句话说,通常模板内的名称查找只会找到在模板定义之前声明的名称(这并不奇怪,因为它与非模板相同)。第二个要点允许找到在模板定义之后声明的名称,但仅限于发生 ADL 时。当参数是 double
.
等基本类型时,情况就不会这样了
考虑以下代码:
#include <iostream>
template<typename T>
void f(T t)
{
(void)t;
std::cout << "templated f(T)\n";
}
template<typename T>
void entry(T t)
{
f(t);
}
void f(double d)
{
(void)d;
std::cout << "normal f(double)\n";
}
int main()
{
double d = 0.0;
entry(d);
return 0;
}
输出:
templated f(T)
我觉得这很奇怪,因为我认为普通函数会比任何模板版本都被选中。为什么会这样?
我在玩耍时注意到的另一件事是:如果我将普通函数 void f(double)
放在模板化的 void entry(T)
函数之前,代码将调用普通函数,基本上输出:
normal f(double)
因此我的另一个问题是:为什么顺序在这个特定示例中很重要?
f(double)
的重载在解析 entry(T)
模板时对编译器不可见。因此,在实例化 entry(T)
模板时,它不会参与重载决策。当涉及到在模板实例化上下文中解析重载时,这只是一个模糊的规则。为了考虑重载,它必须在解析模板定义之前已经在翻译单元中可见。
f
是从属名称,因为它依赖于类型为模板参数的 t
。相关名称的名称查找规则在 [temp.dep.res]/1:
In resolving dependent names, names from the following sources are considered:
- Declarations that are visible at the point of definition of the template.
- Declarations from namespaces associated with the types of the function arguments both from the instantiation context (14.6.4.1) and from the definition context.
换句话说,通常模板内的名称查找只会找到在模板定义之前声明的名称(这并不奇怪,因为它与非模板相同)。第二个要点允许找到在模板定义之后声明的名称,但仅限于发生 ADL 时。当参数是 double
.