Why isn’t the const version selected over the const version for the class?

Below is the test code:

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

Now, calling:

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

Why always choose the non-continent version ? Even creating an operator const int () const; does not affect the call to foo() . Apart from the standard link, can someone explain logically the reason for this?

+6
source share
3 answers

A() provides a temporary object A that is not constant. The expression A() is an rvalue expression, yes, but that does not make object A const-qualified.

Since the object A not constant, the non-constant operator int() is an exact match, and the const operator int() requires a qualification conversion, so non-constant overload is selected as the best match.

If you want it to be const-qualified, you need to explicitly request const-qual A :

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

where identity is defined as

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

Note that there is no difference between operator const int() const and operator int() const : the result is an rvalue, and only r-values ​​of a class type can be const-qualified ( int not a class type).

Note also that there is no difference between void foo(const int) and void foo(int) . The top-level determinant compositions for parameter types do not affect the function type (i.e., the type of both of these declarations is void foo(int) ). Among other reasons, this is because it does not matter to the caller whether the top-level const-level qualifier exists; he must make a copy independently. The top level determiner affects only the definition of a function.

+13
source

James McNellis & rsquo; the answer did cover it all, but he is not afraid (hopefully) with more detailed explanations.

So.

When you call & hellip;

  o.operator int() 

& hellip; then the choice of overload depends entirely on the constant o .

Nothing more.

To find out why, consider this class:

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

Technically, these member functions do not have to be member functions. They could also be selected as free functions. But then they need the Bar argument:

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

And hopefully now it’s easier to see that when you do

 Bar o; f( o ); 

then you can select the first function. And so it is. Because if the second function is selected, you can never get the first. Because if you make a const object, then it breaks the correctness of const to select the first one. Therefore, when the object is const , only the second can be selected, therefore, when it is not const , the first is selected.

In short, the only practical alternative to this rule would always be to choose the second, which would make the first useless, right?

Cheers and hth.,

+5
source

One rule that you should remember about C ++: it never takes into account the value returned when choosing an overload. In this case, since the operator int function does not accept any parameters, it cannot use the parameter list to narrow the selection. All that he can use in it is the constancy of the object from which it is called. Since this is a new temporary object, it is not const, so it does not select const overload.

+4
source

Source: https://habr.com/ru/post/891608/


All Articles