【问题标题】:Doesn't compiler give an ambiguous error for "const" and "not-const" functions编译器不会对“const”和“not-const”函数给出模棱两可的错误
【发布时间】:2018-03-16 16:23:09
【问题描述】:

我在 c++ 结构中重载了 constnon-const 函数。然后,我运行了该程序,我想知道它工作正常,没有模棱两可的错误。

#include <iostream>

struct St 
{
  int f() const 
  { 
      return 1; 
  }

  int f()
  { 
      return 2;
  }
} s;

int main() 
{
    int ret = s.f();  
    std::cout<<ret<<std::endl;
    return 0;
}

所以,我只想知道,为什么编译器不会为“const”和“not-const”函数给出模棱两可的错误?

【问题讨论】:

标签: c++ function c++11 c++14 constants


【解决方案1】:

这是 const overloading,在 C++ 中是 a thing

在这种情况下,编译器确定结构没有重载函数返回类型(当然是disallowed due to ambiguity ),而是具有不同“常量”的重载函数;此处有意义的其他答案之一中的术语。

至于没有编译器错误:

  1. const 重载是 C++ 规范的一部分,因此不会出错
  2. 在编译时,编译器“看到”结构正在返回非 const 环境,因此使用非 const 函数,导致正常操作发生

希望有帮助!

【讨论】:

    【解决方案2】:

    首先是非正式的解释

    让我们按逻辑步骤进行。

    允许并假定使用非常量方法来更改对象。因此它只能在非常量对象上调用。

    不允许使用 const 方法更改对象。因此,它可以在 const 对象上调用,也可以在非 const 对象上调用。

    如果定义了函数的两个重载(const 和非 const),则选择的方法是其 constness 适合对象 constness 的方法。

    标准

    实际上,重载决议对于 const 和非 const 方法没有特殊规则。相反,该标准指定了一个隐式对象参数。考虑到这个隐式对象参数后,您可以应用通常的重载解析规则:

    §13.3.1 候选函数和参数列表 [over.match.funcs]

    1. [...] 一个成员函数被认为有一个额外的参数,称为隐式对象参数,它表示对象为 成员函数已被调用。出于以下目的 重载决议,静态和非静态成员函数都有 隐式对象参数,但构造函数没有。

    2. 类似地,在适当的时候,上下文可以构造一个参数列表,其中包含一个隐含的对象参数来表示对象 进行操作。由于自变量和形参通过以下方式关联 在他们各自的名单中的位置,公约是 隐式对象参数(如果存在)始终是第一个参数 并且隐含的对象参数(如果存在)始终是第一个 论据。

    3. 对于非静态成员函数,隐含对象参数的类型为

      • (4.1) “对 cv X 的左值引用”用于声明没有 ref 限定符或 & ref 限定符的函数
      • (4.2) 对于使用 && ref-qualifier 声明的函数,“对 cv X 的右值引用”

    其中 X 是函数所属的类,而 cv 是 成员函数声明上的 cv 限定。 [ 示例:对于一个 类 X 的 const 成员函数,额外的参数假定为 具有类型“对 const X 的引用”。 —结束示例]用于转换 函数,该函数被认为是类的成员 用于定义类型的隐含对象参数 隐式对象参数。对于引入的非转换函数 通过使用声明到派生类中,该函数是 被认为是派生类的成员 定义隐式对象参数的类型。 [...]

    1. 在重载解析期间,隐含的对象参数与​​其他参数无法区分

    【讨论】:

      【解决方案3】:

      假设类A 的每个成员函数都有一个隐式参数,对于const 成员函数是const A&amp;,对于非const 成员函数是A&amp;。您在重载解决过程上下文中的成员函数将如下所示:

      int f(const St&); 
      int f(St&);
      

      如果重载决议可以选择适当的成员,那么就没有歧义。

      13.3.3.2 [over.ics.rank] 标准转换序列S1 比转换序列更好 标准转换序列S2if
      ...
      13.3.3.2/(3.2.6) S1S2 是引用绑定,除了顶级 cv 限定符和引用初始化的类型之外,引用所引用的类型是相同的类型S2 引用的类型比 S1 初始化的引用所引用的类型更具 cv 限定性。

      因此,重载解析过程选择非常量成员(较少 cv 限定)。

      【讨论】:

      • 从技术上讲,这不是资格转换(该术语是指非顶级资格更改); C++14 中的规则是 [over.ics.rank]/3.1.6 "S1 和 S2 是引用绑定 (8.5.3),并且引用所引用的类型除了顶级 cv 之外的类型相同-qualifiers,并且由 S2 初始化的引用所引用的类型比由 S1 初始化的引用所引用的类型更具 cv 限定。”
      • @MM,谢谢!添加到答案中
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-06-23
      • 2011-06-19
      • 1970-01-01
      • 1970-01-01
      • 2019-08-19
      • 2017-03-11
      • 2020-09-23
      相关资源
      最近更新 更多