调用了错误的重载模板函数
Wrong overloaded template function is called
我有以下带有重载模板函数的代码
#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;
}
我原以为它会失败,因为具有三个参数的最大模板会return 引用一个临时变量(return 由指针模板编辑)。但它可以工作并调用通用模板函数。
问题是为什么不为指针调用模板?
谢谢。
没用。它似乎有效,因为您只使用了前两个参数或三个参数的 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
取消引用会产生误导。
当你调用max(a, b, c)
时,max(const T& a1, const T& a2, const T& a3)
中的T
成为int *
的别名,所以在max(const T& a1, const T& a2, const T& a3 )
max(a,b)
将匹配 max(const T& a1, const T& a2)
typedef int * T;
const T x;
const int * y; //they are different
如果您注释掉 2-argument 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*
.
我有以下带有重载模板函数的代码
#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;
}
我原以为它会失败,因为具有三个参数的最大模板会return 引用一个临时变量(return 由指针模板编辑)。但它可以工作并调用通用模板函数。
问题是为什么不为指针调用模板?
谢谢。
没用。它似乎有效,因为您只使用了前两个参数或三个参数的 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
取消引用会产生误导。
当你调用max(a, b, c)
时,max(const T& a1, const T& a2, const T& a3)
中的T
成为int *
的别名,所以在max(const T& a1, const T& a2, const T& a3 )
max(a,b)
将匹配 max(const T& a1, const T& a2)
typedef int * T;
const T x;
const int * y; //they are different
如果您注释掉 2-argument 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*
.