为什么在类的const版本中选择非const版本?

时间:2011-06-29 03:21:45

标签: c++ const overloading overload-resolution

以下是测试代码:

struct A
{
  operator int ();
  operator int () const;
};

void foo (const int);

现在,在调用时:

foo(A());  // calls A::operator int()

为什么always chooses the non-const version?即使制作operator const int () const;也不会对调用foo()产生任何影响。除了标准参考,有人可以逻辑地解释它背后的原因吗?

3 个答案:

答案 0 :(得分:13)

A()为您提供了一个非const限定的临时A对象。 A()表达式是一个右值表达式,是的,但这不会使A对象成为const限定的。

由于A对象不是const限定的,因此非const operator int()是精确匹配,const operator int()需要限定转换,因此非const重载是被选为最佳匹配。

如果您希望它是const限定的,您需要明确请求const限定A

foo(identity<const A>::type());

其中identity定义为

template <typename T>
struct identity { typedef T type; };

请注意operator const int() constoperator int() const之间确实没有区别:结果是rvalue,只有class-type rvalues可以是const限定的(int不是类类型)。

另请注意,void foo(const int)void foo(int)之间没有区别。参数类型的顶级const限定符不影响函数的类型(即,这两个声明的类型都是void foo(int))。除其他原因外,这是因为调用者是否存在顶级const限定符并不重要;无论如何都必须制作副本。顶级const限定符仅影响函数的定义。

答案 1 :(得分:5)

James McNellis'答案真的涵盖了所有这些,但它并没有伤害(我希望)更多的解释。

所以

当你打电话......

    o.operator int()

...然后过载选择完全取决于 o 的常量。

别无其他。

要了解原因,请考虑此课程:

struct Bar
{
    void f() {}
    void f() const {}
};

从技术上讲,这些成员函数不需要是成员函数。他们也可以被选为独立的职能。但他们需要Bar论证:

struct Bar
{};

void f( Bar& ) {}
void f( Bar const& ) {}

希望现在更容易看到你做的时候

Bar o;
f( o );

然后可以选择第一个函数。就是这样。因为如果选择了第二个函数,那么你永远不会得到第一个函数。因为如果你创建了对象const,那么它会破坏const正确性以选择第一个。因此,当对象为const时,只能选择第二个,因此,当它不是const时,第一个被选中。

简而言之,这条规则的唯一可行替代方案是始终选择第二个,这会使第一个相当无用,是吗?

干杯&amp;第h。,

答案 2 :(得分:4)

您必须记住关于C ++的一条规则:从不会考虑选择重载时返回的值。在这种情况下,由于operator int函数不带参数,因此它不能使用参数列表来缩小选择范围。所有它都可以使用它被调用的对象的常量。由于这是一个新的临时对象,因此它不是const,因此它不会选择const重载。