C++ 模板重载的行为与非模板重载不同
具有以下特征:C++ 模板重载的行为与非模板重载不同,c++,templates,C++,Templates,具有以下特征: #include <iostream> void test(const int& ref){ std::cout << "By reference\n"; } void test(const int *ptr){ std::cout << "By pointer\n"; } template<typename T> void test_template(const T &ref){ s
#include <iostream>
void test(const int& ref){
std::cout << "By reference\n";
}
void test(const int *ptr){
std::cout << "By pointer\n";
}
template<typename T>
void test_template(const T &ref){
std::cout << "By reference\n";
}
template<typename T>
void test_template(const T *ptr){
std::cout << "By pointer\n";
}
int main() {
int *p = 0;
test(p);
test_template(p);
return 0;
}
<>为什么模板版本的行为不同(是C++缺陷还是编译器错误)?< /P> < p>它没有。
test_template(p);
召唤
无效测试模板(int*const&p);
没有歧义,因为
void test\u template(const int*ptr)
在编译器候选列表中排名较低,因为p
是int*
,而不是const int*
让您困惑的是,您的模板没有完全复制重载的行为。当编译器执行(非模板)重载解析时,它发现const int*
比const int&
更匹配,因为指针重载中的int*
不需要转换(但是,两者都有限定符转换,这一点并不重要)
但是,对于模板来说,情况有点不同
这:
其中,T
可以实例化为int
以获得const int*
所以现在编译器必须自问,哪一个匹配更好
,或int*const&ref
const int*ptr
针对int*
const int*
int*
到const int*
的类型转换,而第一个不需要。(指针语法很奇怪,您应该记住,在上面的例子中,剩下的常量是类型的一部分,而不是限定符)。请注意,如果您将p
定义为const int*p=0代码>编译器会选择第二个
要完全重新创建非模板重载的行为,必须显式测试T
是否为指针类型:
template<typename T, typename std::enable_if<!std::is_pointer<T>::value, int>::type = 0>
void test_template(const T& ref){
std::cout << "By reference\n";
}
template<typename T>
void test_template(const T* ptr){
std::cout << "By pointer\n";
}
这是因为排序模板时,会从类型中删除第一个cv限定符和引用。这就给我们留下了
T参考
与
T*ptr
而T*
被认为比T
更专业,因此将根据需要选择第二个
查看当您删除模板中的常量时会发生什么:-)您在模板中可能存在的重复项。您仍然可以将int*
传递给接受const int*
的函数,它只需要执行添加常量的过程,该过程的排序稍微低一点。您是对的。是否有这样一个表达式:void test_template(const int*ptr)
不是首选候选项或类似的东西?@YSC“ranks lower”是这方面的实际措辞。@YSC,与所有重载解析一样,它变得比您希望的更复杂。引用绑定是完全匹配的,不需要转换,属于“标识”转换类别。该标准明确规定,当将cv T&
绑定到已通过的T
时,不会进行转换。指针也是精确匹配的,特别需要资格转换,这属于“资格调整”类别。因为它们都是完全匹配的,所以有一个特殊的规则,基本上说第一个的隐式转换序列更好,因为它是一个身份转换。我的第一个评论实际上是错的。他们的排名相同(完全匹配)。只是因为同一等级比较有特殊规则,所以参考等级比较好。我是在回忆指针一在“表格”中的位置(参见[over.ics.scs])。
void test_template<int*>(int* const& p);
template<typename T>
void test_template(const T &ref){
std::cout << "By reference\n";
}
template<typename T>
void test_template(const T *ptr){
std::cout << "By pointer\n";
}
template<typename T, typename std::enable_if<!std::is_pointer<T>::value, int>::type = 0>
void test_template(const T& ref){
std::cout << "By reference\n";
}
template<typename T>
void test_template(const T* ptr){
std::cout << "By pointer\n";
}
template<typename T>
void test_template(const T &ref){
std::cout << "By reference\n";
}
template<class T>
void test_template(T* const ptr){
std::cout << "By pointer\n";
}