我有以下带有重载模板函数的代码
#include <iostream>
using namespace std;
template <class T>
const T& max(const T& a1, const T& a2)
{
cout << "general template" << endl;
return (a1 < a2) ? a2 : a1;
}
template <class T>
const T* max(const T* a1, const T* a2)
{
cout << "max for pointers" << endl;
return (a1 < a2) ? a2 : a1;
}
template <class T>
const T& max(const T& a1, const T& a2, const T& a3)
{
cout << "general template with three parameters" << endl;
return ::max(::max(a1, a2), ::max(a1, a2));
}
int main()
{
int* a = new int(5);
int* b = new int(56);
int* c = new int(2);
int*const &g = ::max(a, b, c);
cout << *g << endl;
return 0;
}
我原以为它会失败,因为带有三个参数的max模板会返回对临时变量的引用(由指针模板返回)。但它可以工作并调用通用模板功能。
问题是为什么没有为指针调用模板?
感谢。
答案 0 :(得分:2)
它不起作用。它似乎有效,因为你只使用前两个参数或三个参数max函数。
template <class T>
const T& max(const T& a1, const T& a2, const T& a3)
{
cout << "general template with three parameters" << endl;
return ::max(
::max(a1, a2),
::max(a1, a2)); // HERE
}
更正显示正在发生的事情:您正在比较指针地址。
请参阅here in action。
您的指针重载未被调用,因为参考版本更适合:a1
等是const引用(指针,但很好)。因此,参考版本在重载分辨率方面是完美的匹配。
我想要实现你想要的东西,你需要一些SFINAE魔法。
我想补充一点:由于比较指针是C ++中的常见操作,因此在比较之前对指针进行一些max
取消引用会非常误导。
答案 1 :(得分:2)
如果你为引用注释掉2参数max
的定义,你会发现代码没有编译。 MSVC ++ 2013在第22行给出的错误是:
error C2440: 'return' : cannot convert from 'const int *' to 'int *const &'
这似乎是为什么始终选择max
引用的原因:对于指针,max
的模板替换失败。
如果将代码更改为以下内容,则会调用指针模板:
#include <iostream>
using namespace std;
template <class T>
T max(const T& a1, const T& a2)
{
cout << "general template" << endl;
return (a1 < a2) ? a2 : a1;
}
template <class T>
T* max(T* a1, T* a2)
{
cout << "template for pointers" << endl;
return (a1 < a2) ? a2 : a1;
}
template <class T>
T max(const T& a1, const T& a2, const T& a3)
{
cout << "general template with three parameters" << endl;
return ::max(::max(a1, a2), a3);
}
int main()
{
int* a = new int(5);
int* b = new int(56);
int* c = new int(2);
int* g = ::max(a, b, c);
cout << *g << endl;
return 0;
}
如果注释掉指针模板的定义,则调用引用模板。对于引用模板的指针的模板的偏好似乎发生,因为类型已经是指针。
以下是模板匹配顺序的一些解释:What are the rules for choosing from overloaded template functions?
编辑:可以用另一种方式更改OP的代码,以便MSVC ++ 2013更喜欢基于引用的模板到基于指针的模式:#include <iostream>
using namespace std;
template <class T>
T max(const T& a1, const T& a2)
{
cout << "general template" << endl;
return (a1 < a2) ? a2 : a1;
}
template <class T>
const T* max(const T* a1, const T* a2)
{
cout << "template for pointers" << endl;
return (a1 < a2) ? a2 : a1;
}
template <class T>
T max(const T& a1, const T& a2, const T& a3)
{
cout << "general template with three parameters" << endl;
return const_cast<const T>(::max(::max(a1, a2), a3));
}
int main()
{
int* a = new int(5);
int* b = new int(56);
int* c = new int(2);
int* g = ::max(a, b, c);
cout << *g << endl;
return 0;
}
这是因为在这个版本中,基于指针的模板定义为其参数类型提供了额外的限定符:它们不仅仅是T*
,而是const T*
。
答案 2 :(得分:1)
当您致电max(a, b, c)
时,T
中的max(const T& a1, const T& a2, const T& a3)
变为int *
的别名,因此在max(const T&amp; a1,const T&amp; a2,const T&amp; A3)
max(a,b)
将匹配max(const T& a1, const T& a2)
typedef int * T;
const T x;
const int * y; //they are different