为什么类的 const 版本选择非常量版本?
以下是测试代码:
struct A
{
operator int ();
operator int () const;
};
void foo (const int);
现在,调用时:
foo(A()); // calls A::operator int()
为什么总是选择非常量版本?即使使 operator const int () const;
也不会对调用 foo()
产生任何影响。除了标准参考之外,有人可以逻辑地解释其背后的原因吗?
Following is the test code:
struct A
{
operator int ();
operator int () const;
};
void foo (const int);
Now, upon invoking:
foo(A()); // calls A::operator int()
Why does it always chooses the non-const version ? Even making operator const int () const;
doesn't have any effect on invoking foo()
. Apart from standard reference, can someone explain logically, the reason behind it ?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
A()
为您提供一个非 const 限定的临时A
对象。是的,A()
表达式是一个右值表达式,但这并不会使A
对象成为 const 限定的。由于
A
对象不是 const 限定的,因此非 constoperator int()
与 constoperator int()
完全匹配需要进行资格转换,因此选择非常量重载作为最佳匹配。如果您希望它是 const 限定的,则需要显式请求 const 限定的
A
:其中
identity
定义为请注意,之间实际上没有区别
operator const int() const
和operator int() const
:结果是右值,并且只有类类型右值可以是 const 限定的(int
代码> 不是类类型)。另请注意,您拥有的
void foo(const int)
和void foo(int)
之间没有区别。参数类型的顶级 const 限定符不会影响函数的类型(即,这两个声明的类型都是void foo(int)
)。除其他原因外,这是因为对于调用者来说是否有顶级 const 限定符并不重要;无论如何,它都必须复制一份。顶级 const 限定符仅影响函数的定义。A()
gives you a temporaryA
object that is not const-qualified. TheA()
expression is an rvalue expression, yes, but that does not make theA
object const-qualified.Since the
A
object is not const-qualified, the non-constoperator int()
is an exact match and the constoperator int()
requires a qualification conversion, so the non-const overload is selected as the best match.If you want it to be const-qualified, you'd need to explicitly request a const-qualified
A
:where
identity
is defined asNote that there is really no difference between
operator const int() const
andoperator int() const
: the result is an rvalue and only class-type rvalues can be const-qualified (int
is not a class type).Note also that there is no difference between the
void foo(const int)
that you have andvoid foo(int)
. Top-level const-qualifiers on parameter types do not affect the type of the function (i.e., the type of both of those declarations isvoid foo(int)
). Among other reasons, this is because it doesn't matter to the caller whether there is a top-level const-qualifier; it has to make a copy regardless. The top-level const-qualifier affects only the definition of the function.詹姆斯·麦克内利斯' 的答案确实涵盖了所有内容,但(我希望)更多解释也不会造成伤害。
所以。
当您调用……
时,重载选择完全取决于
o
的常量。没有别的了。
要了解原因,请考虑此类:
从技术上讲,这些成员函数不需要是成员函数。它们也可以被选择为独立的功能。但是他们需要
Bar
参数:希望现在更容易看到,当您
这样做时,可以选择第一个函数。事实也是如此。因为如果选择了第二个功能,那么您将永远无法获得第一个功能。因为如果您将对象设置为 const,那么选择第一个对象就会破坏 const 的正确性。因此,当对象为
const
时,只能选择第二个,因此,当对象不是const
时,将选择第一个。简而言之,该规则的唯一实际替代方案是始终选择第二个规则,这将使第一个规则变得毫无用处,是吗?
干杯&呵呵,
James McNellis’ answer really covered it all, but it doesn’t hurt (I hope) with more explanations.
So.
When you call …
… then the overload selection depends entirely on the constness of
o
.Nothing else.
To see why, consider this class:
Technically those member functions do not need to be member functions. They could just as well have been chosen to be free standing functions. But then they need
Bar
argument:And hopefully now it's easier to see that when you do
then the first function can be selected. And so it is. Because if the second function was selected, then you could never get the first one. Because if you make the object
const
, then it would breakconst
correctness to select the first one. So when the object isconst
only the second can be selected, hence, when it is notconst
the first one is selected.In short, the only practical alternative to this rule would be to always select the second one, which would make the first one rather useless, yes?
Cheers & hth.,
关于 C++,您必须记住一条规则:它从不考虑选择重载时返回的值。在这种情况下,由于
operator int
函数不带任何参数,因此它也无法使用参数列表来缩小选择范围。它可以使用它所调用的对象的常量。由于这是一个新的临时对象,它不是 const,因此它不会选择 const 重载。One rule you have to remember about C++: it never takes into account the value that is being returned when it selects an overload. In this case since the
operator int
function takes no parameters, it can't use the parameter list to narrow down the choices either. All it can use it the constness of the object that it's being called from. Since this is a new temporary object, it's not const, so it doesn't choose the const overload.