Zho*_*eng 17 c++ dependent-name function-templates name-lookup unqualified-name
I was reading about template functions and got confused by this problem:
#include <iostream>
void f(int) {
std::cout << "f(int)\n";
}
template<typename T>
void g(T val) {
std::cout << typeid(val).name() << " ";
f(val);
}
void f(double) {
std::cout << "f(double)\n";
}
template void g<double>(double);
int main() {
f(1.0); // f(double)
f(1); // f(int)
g(1.0); // d f(int), this is surprising
g(1); // i f(int)
}
Run Code Online (Sandbox Code Playgroud)
The results are the same if I don't write template void g<double>(double);.
I think g<double> should be instantiated after f(double), and therefore the call to f in g should call f(double). Surprisingly, it still calls f(int) in g<double>. Can anyone help me understand this?
After reading the answers, I figured out what my confusion really is.
Here is an updated example. It is mostly unchanged except that I added a specialization for g<double>:
#include <iostream>
void f(int){cout << "f(int)" << endl;}
template<typename T>
void g(T val)
{
cout << typeid(val).name() << " ";
f(val);
}
void f(double){cout << "f(double)" << endl;}
//Now use user specialization to replace
//template void g<double>(double);
template<>
void g<double>(double val)
{
cout << typeid(val).name() << " ";
f(val);
}
int main() {
f(1.0); // f(double)
f(1); // f(int)
g(1.0); // now d f(double)
g(1); // i f(int)
}
Run Code Online (Sandbox Code Playgroud)
With the user specialization, g(1.0) behaves as I expected.
Should the compiler not automatically do this same instantiation for g<double> in the same place (or even after main(), as described in section 26.3.3 of The C++ Programming Language, 4th edition)?
名称f是一个从属名称(它T通过参数依赖val),它将分解为两个步骤:
- 非ADL查找检查从模板定义上下文可见的函数声明。
- ADL检查从模板定义上下文或模板实例化上下文可见的函数声明。
void f(double)在模板定义上下文中不可见,并且ADL也不会找到它,因为
对于基本类型的参数,关联的名称空间和类的集合为空
我们可以稍微修改一下您的示例:
struct Int {};
struct Double : Int {};
void f(Int) {
std::cout << "f(Int)";
}
template<typename T>
void g(T val) {
std::cout << typeid(val).name() << ' ';
f(val);
// (f)(val);
}
void f(Double) {
std::cout << "f(Double)";
}
int main() {
g(Double{});
}
Run Code Online (Sandbox Code Playgroud)
现在,ADL将void f(Double)在第二步中找到,输出将是6Double f(Double)。我们可以通过写(f)(val)(或::f(val))而不是禁用ADL f(val)。然后输出将6Double f(Int)与您的示例一致。
小智 5
The problem is f(double) has not been declared at the point where you call it; if you move its declaration in front of the template g, it will get called.