Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/148.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 模板重载的行为与非模板重载不同_C++_Templates - Fatal编程技术网

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
答案是第一个。鉴于引用和cv限定符在订购模板之前已被删除,我们只能进行比较

  • 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";
}