英文:
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++20的over.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 << "Bar\n"; return {}; }
operator Baz() const { std::cout << "Baz\n"; return {}; }
};
void foo(const Foo &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{} -> user conversion -> Bar -> const Foo&
X{} -> user conversion -> Buz -> const Foo&
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&
的参数初始化一个类型为 X
的 prvalue。
这属于[dcl.init.ref]/5.3.2,该部分指示我们通过重载决议选择一个转换函数。
operator Bar()
和 operator Baz() const
都是候选项,但前者更匹配,因为其对象参数不是 const
([over.ics.rank]/3.2.6)。
因此,从 X
到 const Foo&
的(唯一)转换序列经过 Bar
。而且我们从未将其与另一个转换序列进行排名,因为只有一个 foo
。
在这种情况下会出现歧义:
void foo(Bar);
void foo(Baz);
foo(X());
现在这个调用是模棱两可的,因为从 X
到 Bar
的 ICS 与 X
-> Baz
是无法区分的,尽管其第一个标准转换序列更好。
英文:
foo(X{})
attempts to initialize a parameter of type const Foo&
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&
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论