调用错误的重载模板函数

时间:2015-07-05 07:51:06

标签: c++ templates overloading

我有以下带有重载模板函数的代码

#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模板会返回对临时变量的引用(由指针模板返回)。但它可以工作并调用通用模板功能。
问题是为什么没有为指针调用模板?

感谢。

3 个答案:

答案 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