Overload resolution with const-qualification 超载解析与const限定

huangapple go评论63阅读模式
英文:

Overload resolution with const-qualification

问题

Here is the translation of the code you provided:

让我们考虑一个简化的例子

struct Foo {};
struct Bar : Foo {};
struct Baz : Foo {};

struct X {
  operator Bar() { std::cout << "Bar\n"; return {}; }
  operator Baz() const { std::cout << "Baz\n"; return {}; }
};

void foo(const Foo &f) {}

int main() {
  foo(X{});
}

在这里,GCC和clang都打印"Bar",请参见[godbolt示例][1]

我很难理解为什么会这样。

rvalue对象中调用带有const注释的方法没有问题,参见[此示例][2]

所以让我们建立ICS

X{} -> 用户转换 -> Bar -> const Foo&
X{} -> 用户转换 -> Buz -> const Foo&

这两个ICS都有1个用户转换和等效的标准转换尾部。根据[C++20over.ics.rank][over.ics.rank],这应该是模棱两可的。

有人可以帮助解释发生了什么吗?我不认为主流编译器都同意这里有问题。

[1]: https://godbolt.org/z/cYhxW4j4G
[2]: https://godbolt.org/z/3fjEvz66j

Please note that code translation may not be perfect, and it's important to review the translated code for accuracy and any potential issues.

英文:

Lets consider simple reduced example

struct Foo {};
struct Bar : Foo {};
struct Baz : Foo {};

struct X {
  operator Bar() { std::cout &lt;&lt; &quot;Bar\n&quot;; return {}; }
  operator Baz() const { std::cout &lt;&lt; &quot;Baz\n&quot;; return {}; }
};

void foo(const Foo &amp;f) {}

int main() {
  foo(X{});
}

Here both GCC and clang are printing "Bar", see godbolt example

I am struggling to understand why.

There is no problem to call const-annotated method in rvalue object, see this example

So lets build ICS:

X{} -&gt; user conversion -&gt; Bar -&gt; const Foo&amp;
X{} -&gt; user conversion -&gt; Buz -&gt; const Foo&amp;

Both ICS have 1 user conversion and equivalent standard conversion tail. This shall be ambiguity by [over.ics.rank] C++20.

Can someone help to motivate what happens? I don't believe both mainline compilers agree and wrong here.

答案1

得分: 1

foo(X{}) 试图使用类型为 const Foo&amp; 的参数初始化一个类型为 X 的 prvalue。

这属于[dcl.init.ref]/5.3.2,该部分指示我们通过重载决议选择一个转换函数。

operator Bar()operator Baz() const 都是候选项,但前者更匹配,因为其对象参数不是 const ([over.ics.rank]/3.2.6)。

因此,从 Xconst Foo&amp; 的(唯一)转换序列经过 Bar。而且我们从未将其与另一个转换序列进行排名,因为只有一个 foo


在这种情况下会出现歧义:

void foo(Bar);
void foo(Baz);
foo(X());

现在这个调用是模棱两可的,因为从 XBar 的 ICS 与 X -> Baz 是无法区分的,尽管其第一个标准转换序列更好。

英文:

foo(X{}) attempts to initialize a parameter of type const Foo&amp; with a prvalue of type X.

This falls under [dcl.init.ref]/5.3.2, which directs us to [over.match.ref] to select a conversion function through overload resolution.

Both operator Bar() and operator Baz() const are candidates, but the former is a better match because its object parameter is not const ([over.ics.rank]/3.2.6).

So, the (only) conversion sequence from X to const Foo&amp; goes through Bar. And we never rank it against another conversion sequence because there is only one foo anyway.


An ambiguity would arise in a situation like this:

void foo(Bar);
void foo(Baz);
foo(X());

Now the call is ambiguous because the ICS from X to Bar is indistinguishable from X -> Baz, despite its first standard conversion sequence being better.

huangapple
  • 本文由 发表于 2023年5月7日 03:25:05
  • 转载请务必保留本文链接:https://go.coder-hub.com/76190714.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定