模板和非模板函数之间的C ++重载解析

时间:2018-08-16 15:00:38

标签: c++ templates overload-resolution

我对模板和非模板函数之间的c ++重载解析感到困惑,以下是示例:

class Stream {};

struct M
{
    M(float v) {}
};

template <class T>
Stream& operator<<(Stream& stream, T& v) {}

Stream& operator<<(Stream& stream, const M& v) {}

int main()
{
    Stream stream;
    int a = 1;

    stream << a; // sample 1
    stream << a * a; // sample 2

    return;
}

在这里,示例1调用了模板函数。样本2提供了一个int&&类型的参数,该参数可以隐式转换为const M&,调用非模板的参数,然后调用带有T = const int的模板的参数。

样本2的过载分辨率会发生什么?

3 个答案:

答案 0 :(得分:5)

这确实与模板无关。在

stream << a * a;

a * a实现一个右值。由于您的模板函数采用T&,因此它无法绑定到临时模板,因此将其作为可行的重载丢弃。

这将为您提供用户定义的M转换和

Stream& operator<<(Stream& stream, const M& v)

是唯一可行的重载。


如果您更改模板以使用转发参考,例如

template <class T>
Stream& operator<<(Stream& stream, T&& v) 

然后在两种情况下都将被调用,因为您将获得完全匹配。请注意,您应该使用SFINAE约束T,否则,此重载将非常适合所有应用。

您还可以使用

template <class T>
Stream& operator<<(Stream& stream, const T& v)

答案 1 :(得分:2)

一个模板使用T&接受参数,即对非常量的左值引用。 a * a是一个右值,不能绑定到非常量的左值引用(顺便说一句,它可以绑定到左值对const或右值引用)。这样就不会考虑模板一。

答案 2 :(得分:2)

与左值一起使用时,模板是更好的匹配,因为它不需要调用从intM的转换。

但是,由于非常量左值引用不能绑定到右值(通过乘积产生),因此无法使用此重载,因此编译器会退回转换。