为什么选择这种转换运算符的重载?

ava*_*kar 27 c++ language-lawyer overload-resolution c++17

考虑以下代码

struct any
{
    template <typename T>
    operator T &&() const;

    template <typename T>
    operator T &() const;
};
int main()
{
    int a = any{};
}
Run Code Online (Sandbox Code Playgroud)

这里第二个转换运算符由重载决议选择。为什么?

据我了解,这两个运算符分别推导为operator int &&() constoperator int &() const。两者都在可行的功能集中。通读 [over.match.best] 并没有帮助我弄清楚为什么后者更好。

为什么后者的功能比前者好?

Bri*_*ian 13

T&首选返回的转换运算符,因为它比返回的转换运算符更专业T&&

参见 C++17 [temp.deduct.partial]/(3.2):

在调用转换函数的上下文中,使用转换函数模板的返回类型。

和/9:

如果,对于给定类型,扣除在两个方向成功(即,类型是上述变换后相同的)和二者PA分别引用类型(与类型被替换之前上文提及): -如果从参数模板的类型是左值引用而参数模板中的类型不是,参数类型不被认为至少与参数类型一样特殊;...


Yak*_*ont 12

推导出来的返回值转换运算符有点奇怪。但核心思想是它就像一个函数参数来选择使用哪个。

之间作出决定时T&&,并T&T&在重载决策规则的胜利。这是为了允许:

template<class T>
void f( T&& ) { std::cout << "rvalue"; }
template<class T>
void f( T& ) { std::cout << "lvalue"; }
Run Code Online (Sandbox Code Playgroud)

上班。 T&&可以匹配左值,但是当左值和通用引用重载都可用时,首选左值。

正确的转换运算符集可能是:

template <typename T>
operator T&&() &&;

template <typename T>
operator T &() const; // maybe &
Run Code Online (Sandbox Code Playgroud)

甚至

template <typename T>
operator T() &&;

template <typename T>
operator T &() const; // maybe &
Run Code Online (Sandbox Code Playgroud)

以防止失败的终身延长咬你。

3 用于确定排序的类型取决于完成偏序的上下文:

[剪辑]

(3.2) 在调用转换函数的上下文中,使用转换函数模板的返回类型。

然后在选择重载时最终取决于“更专业”的规则:

(9.1) 如果参数模板中的类型是左值引用而参数模板中的类型不是,则认为参数类型至少不像参数类型那样特殊;除此以外,

因此operator T&&至少不如 专门化operator T&,同时没有规则状态operator T&至少不如 专门化operator T&&,因此operator T&比 更专门化operator T&&

在其他条件相同的情况下,更专业的模板胜过更少的重载解决方案。