模板重载中更特例化的实例如何理解?

新手上路,请多包涵

问题来自于c++ primer 5th的练习16.49

template<typename T> void g(T);
template<typename T> void g(T*);
int i = 42, *p = &i;
g(p);    //调用的哪个版本?

上述问题有两个候选函数, 都为精确匹配, 个人理解的答案是此调用有歧义.
实际编译器选择的是第二个实例void g<int>(int*), 请问为什么? 结果没有歧义的话, 只能说明选用的是更特例化的版本, 但是第二个实例哪里比第一个实例更特例化了?

void g<int*>(int*);
void g<int>(int*);

更特例化指的是形参类型更接近于实参类型吗?

阅读 1.8k
2 个回答

C++ 标准有一章讲模板函数重载时怎么排序:
temp.func.order

问题里是比较简单的情况,可以用两个模板版函数互相推导来判断。如果一个成功、一个失败,那么就可以确定谁更特化了。

具体就是
对于 template<typename T> void g(T); ,生成一个虚拟函数调用 g(class foo); ,然后推导 template<typename T> void g(T*)中的 T ,失败;
对于 template<typename T> void g(T*); ,生成一个虚拟函数调用 g(class bar*); ,然后推导 template<typename T> void g(T)中的 T ,成功(T=class bar*);

于是认为,template<typename T> void g(T*) 更特化。

通俗一点讲,就是能使用 template<typename T> void g(T*) 的函数调用,都可以使用 template<typename T> void g(T) ; 但是反过来就不行。于是 template<typename T> void g(T*) 更特化。

你的理解基本正确。在这个例子中,实际上第二个模板函数更特例化。当编译器进行模板参数推导时,它会选择最匹配的模板。在这里,两个模板函数的定义如下:

template<typename T> void g(T);
template<typename T> void g(T*);

当调用g(p)时,p的类型是int*。在这种情况下,编译器会尝试推导两个模板函数的模板参数。对于第一个函数模板,编译器会推导T为int*,所以实例化的函数签名是void g<int*>(int*)。对于第二个函数模板,编译器会推导T为int,实例化的函数签名是void g<int>(int*)

现在有两个候选函数:void g<int*>(int*)void g<int>(int*)。在这种情况下,编译器会选择更特例化的函数模板。更特例化的模板是那些形参类型更接近实参类型的模板。这里,第二个模板函数void g<int>(int*)更特例化,因为它的形参类型int*恰好与实参类型int*相匹配。而第一个模板函数void g<int*>(int*)需要一次额外的间接寻址,即int**int*。因此,编译器选择第二个模板函数作为实例化的函数。

所以,当调用g(p)时,编译器会选择第二个模板函数void g<int>(int*),并不会产生歧义。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题