Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why non-const version is selected over the const version for class?

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 ?

like image 287
iammilind Avatar asked Jun 29 '11 03:06

iammilind


People also ask

How is it possible to have both const and non const version of a function?

There are legitimate uses of having two member functions with the same name with one const and the other not, such as the begin and end iterator functions, which return non-const iterators on non-const objects, and const iterators on const objects, but if it's casting from const to do something, it smells like fish.

What will happen if a const object calls a non const member function?

If the function is non-constant, then the function is allowed to change values of the object on which it is being called. So the compiler doesn't allow to create this chance and prevent you to call a non-constant function on a constant object, as constant object means you cannot change anything of it anymore.

Can a const reference be bound to a non const object?

No. A reference is simply an alias for an existing object. const is enforced by the compiler; it simply checks that you don't attempt to modify the object through the reference r .

Can non const functions call const functions?

CPP. When a function is declared as const, it can be called on any type of object. Non-const functions can only be called by non-const objects.


2 Answers

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

Since the A object is not const-qualified, the non-const operator int() is an exact match and the const operator 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:

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

where identity is defined as

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

Note that there is really no difference between operator const int() const and operator 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 and void 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 is void 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.

like image 175
James McNellis Avatar answered Oct 07 '22 00:10

James McNellis


James McNellis’ answer really covered it all, but it doesn’t hurt (I hope) with more explanations.

So.

When you call …

    o.operator int()

… then the overload selection depends entirely on the constness of o.

Nothing else.

To see why, consider this class:

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

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:

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 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 break const correctness to select the first one. So when the object is const only the second can be selected, hence, when it is not const 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.,

like image 32
Cheers and hth. - Alf Avatar answered Oct 07 '22 01:10

Cheers and hth. - Alf