const成员函数优先于返回值类型匹配

时间:2016-09-13 08:25:17

标签: c++

Y::test1()中,非常量X::operator void*()优先于看似更好的匹配,X::operator bool() const - 为什么?标准中描述了这种现象在哪里?

#include <iostream>

struct X {
  operator void*()      { std::cout << "  operator void*()\n"; return nullptr; }
  operator bool() const { std::cout << "  operator bool()\n";  return true; }
};

struct Y {
  X x;
  bool test1()       { std::cout << "test1()\n"; return x; }
  bool test2() const { std::cout << "test2()\n"; return x; }
};

int main() {
  Y y;
  y.test1();
  y.test2();
}

输出:

test1()
  operator void*()
test2()
  operator bool()

2 个答案:

答案 0 :(得分:10)

首先:将return语句中的表达式转换为函数的返回类型时,规则与初始化相同(参见[conv] /2.4和[conv] / 3)。

因此,我们可以使用此示例检查代码的行为(使用相同的X,但没有Y):

X test1;
bool b1 = test1;

X const test2;
bool b2 = test2;

(在调用y.test2()中,this->x的类型是X const,这就是拥有const成员函数的意义。如果我们转换为bool而不是编写初始化语句,它也会是相同的。

在这种情况下处理重载解析的标准部分是[over.match.conv],这里是C ++ 14文本(为简洁起见,省略一些):

  

13.3.1.5按转换函数初始化[over.match.conv]

     

1 在8.5中指定的条件下,作为非类型对象初始化的一部分,可以调用转换函数将类类型的初始化表达式转换为对象的类型被初始化。 [...]

     

2 参数列表有一个参数,它是初始化表达式。 [注意:此参数将与转换函数的隐式对象参数进行比较。 -end note ]

test2情况很简单 - 无法在const对象上调用非const成员函数,因此从不考虑operator void*,只有一个候选者,不需要重载决策。调用operator bool()

因此,对于本文的其余部分,我将只讨论test1案例。我在上述引文中省略的部分涵盖了operator booloperator void*()都是test1案例的候选函数。

重要的是要注意重载分辨率在这两个候选函数中选择,而是考虑两个隐式转换序列的情况,每个隐式转换序列包含一个用户 - 定义转换。为了支持这一点,请查看[over.best.ics]的第一句话:

  

隐式转换序列是一系列转换,用于将函数调用中的参数转换为被调用函数的相应参数的类型。

我们不会在函数调用中转换参数。关于隐式转换序列的规则在我们对候选函数进行排序时起作用:规则应用于每个候选函数的每个参数,我们将在稍后看到。

现在我们查看最佳可行功能的规则,以确定选择这两个候选功能中的哪一个。我将跳过[over.match.viable],它澄清了这两个候选者是否可行,并且[over.match.best]。

该部分的关键部分是[over.match.best] /1.2:

  

ICSi(F)表示隐式转换序列,它将列表中的第i个参数转换为可行函数F的第i个参数的类型.13.3.3.1定义隐式转换序列和13.3.3.2定义了一个隐式转换序列对于更好的转换序列意味着什么   或者转换顺序比另一个更差。

这里,i == 1,上面[over.match.conv] / 2解释的只有一个参数test1 - 参数是初始化表达式test1; “可行函数的参数”是X的成员函数的隐式对象参数。

现在隐式转化顺序规则适用:

  • operator void*()不需要转换 - 参数为X且参数为X&
  • operator bool() const需要进行资格转换 - 参数为X,参数为X const&

无转化优于资格转换([over.ics.rank] /3.1.1)。因此ICS1(operator void*())是比ICS1(operator bool() const)更好的转换序列;所以此时operator void*()获胜([over.match.best] /1.3)。

后面的段落[over.match.best] /1.4解释了如果这两个序列都不是更好的话会发生什么:我们只会继续比较候选函数的返回类型的标准转换序列到正在初始化的类型。

您可以通过将X成员更改为operator void*() const来探索此案例。现在两个ICS1序列在/1.3之间是无法区分的,所以我们进入/1.4,此时operator bool() const获胜,因为它转换为bool是身份,而operator void*() const仍需要布尔值转换。

答案 1 :(得分:7)

隐式this指针是非const。所以重载解析发生在所有const方法的集合上(包括模板 - 这是pub测验的一个),之前 / em>考虑任何const方法。

如果你理解了const,那么函数被标记const并不能使它更适合非this #models.py class TableName(models.Model): is_qualified = False title = models.CharField(max_length=300, blank=False) description = models.TextField(max_length=500, default="DEFAULT VALUE") video = models.FileField(upload_to='somepath') picture_thumbnail = models.ImageField(upload_to='somepath') 指针。

请参阅主要代表标准的http://en.cppreference.com/w/cpp/language/overload_resolution