Calling a Const Function Rather Than Its Non-Const Version

Calling a const function rather than its non-const version

If you have two overloads that differ only in their const-ness, then the compiler resolves the call based on whether *this is const or not. In your example code, test is not const, so the non-const overload is called.

If you did this:

testType test;
const testType &test2 = test;
test2->x();

you should see that the other overload gets called, because test2 is const.

Const function calling non const or vice versa (to avoid duplication)?

If you have to make a function that is const-agnostic, and avoids duplication, one neat way to do it is delegating implementation to a template, for example

class Foo {
private:

int my_int;
template <typename ThisPtr>
static auto& get(ThisPtr this_ptr) {
return this_ptr->my_int;
}

public:
int& get() {
return get(this);
}

const int& get() const {
return get(this);
}
};

This way you are free from the fear associated with using const_cast, mutable and other stuff that goes into trying to reduce code duplication in cases like this. If you get something wrong, the compiler will let you know.

How to prefer calling const member function and fallback to non-const version?

This seems to work:

#include <type_traits>
#include <iostream>

template<typename T, typename=void>
struct find_a_drink {

void operator()(T &t) const
{
t.get_drink();
}
};

template<typename T>
struct find_a_drink<T,
std::void_t<decltype( std::declval<const T &>()
.get_drink())>
> {

void operator()(T &t) const
{
static_cast<const T &>(t).get_drink();
}
};

template<typename T>
void drink_from(T &&t)
{
find_a_drink<std::remove_reference_t<T>>{}(t);
}

/// v1
class Bar1
{
public:
void get_drink()
{
std::cout << "non-const get_drink() called (Bar1)" << std::endl;
}
};

class Bar2
{
public:
void get_drink()
{
std::cout << "non-const get_drink() called (Bar2)" << std::endl;
}

void get_drink() const
{
std::cout << "const get_drink() called (Bar2)" << std::endl;
}
};

int main()
{
Bar1 b1;
Bar2 b2;

drink_from(b1);
drink_from(b2);
return 0;
}

Result:

non-const get_drink() called (Bar1)
const get_drink() called (Bar2)

How to call a non-const function within a const function (C++)

you should alter your program to use/declare const correctly...

one alternative is to use const_cast.

Same function with const and without - When and why?

But why would you have both functions in one and the same class definition?

Having both allows you to:

  • call the function on a mutable object, and modify the result if you like; and
  • call the function on a const object, and only look at the result.

With only the first, you couldn't call it on a const object. With only the second, you couldn't use it to modify the object it returns a reference to.

And how does the compiler distinguish between these?

It chooses the const overload when the function is called on a const object (or via a reference or pointer to const). It chooses the other overload otherwise.

I believe that the second f() (with const) can be called for non-const variables as well.

If that were the only overload, then it could. With both overloads, the non-const overload would be selected instead.

How to explicitly call const version of the member function?

C++17 will introduce std::as_const, which is a really simple utility that you can implement yourself until then:

A a;
std::as_const(a).mass();

Prevent const function being called for non-const object

You can explicitly delete the following version

void operator()( int const * ) = delete;

to disallow

s1( &i2 ); // 2

and

void operator()( int * ) const = delete;

to disallow

s2( &i1 ); // 3

const/non-const objects calling const/non-const functions

Let's say we have a class A like that described by the OP (i.e. with a const and non-const version of the same member function, named A::fun() const and A::fun() respectively.

The difference between the two versions is that the specification of A::fun() const function is that it will not logically change state the object it is called on, but that A::fun() is permitted to.

If a expression/statement some_object.fun() calls A::fun() const then it will not change the logical state (i.e. value of non-static members that are not specified as mutable) of some_object. (Assuming there is no undefined behaviour present).

Similarly, if the expression some_object.fun() calls A::fun() (the non-const version), then the state of some_object may be logically changed.

Now, we need to look at what the implementation (aka compiler) should do when it encounters an expression of the form some_object.fun(). Since there are both A::fun() const and A::fun(), it is necessary to apply some criteria for the implementation to decide which one to call.

The first - simple - case is that some_object is declared const (or is a const reference to an A).

const A some_object;
some_object.fun();

This declaration expresses an intent, by the programmer, that logical state of some_object will not be changed. The non-const version of fun() is permitted to change the state of some_object, so it is never a valid match for some_object.fun() - if the implementation chooses this, it must then issue a diagnostic (which, among other things, usually means that the code will not compile). All this means that A::fun() const is the only permitted choice in this case.

The second case is that some_object is NOT declared as const.

A some_object;
some_object.fun();

The declaration expresses intent, by the programmer, to permit (or, at least, not disallow) changing the logical state of some_object. Since A has both a const and a non-const version of fun() there are three possible choices that could (notionally) have been enshrined in the standard.

  1. Prefer to call A::fun() const over A::fun() (the non-const version). There is no harm in not changing an object for which change is permitted. However, this option also eliminates any circumstances in which the non-const function A::fun() would ever be called. There would therefore be no purpose in permitting a class to have both versions.
  2. Prefer to call A::fun() over the A::fun() const. There is no harm in this choice, since there is no harm in changing an object when change is permitted.
  3. Deem A::fun() and A::fun() const to be equally good candidate. This introduces ambiguity for the compiler since there are two equally valid alternatives, and no reason to prefer one over the other, so a diagnostic is again required. As for option (1), this also means there are no circumstances in which the non-const function would ever be called, so there is no point in permitting a class to have both versions.

Option (2) above is what the standard requires. It means that there are defined circumstances in which each of A::fun() and A::fun() const may be called (a non-const and a const object respectively) and minimal uncertainty in the choice.

With both options (1) and (3), there is no point in the programmer providing both A::fun() and A::fun() const - or for the standard to even allow the programmer to provide both versions - since there are no circumstances in which the non-const version would ever be called when given a statement or expression of the form some_object.fun(). To introduce either option (1) or (3) there would need to be a (possibly complicated) set of additional clauses in the standard that specify when the non-const version of the function should be called. While the C++ standardisation committee is notable for embracing obscure and complicated rules (possibly excessively) it appears they didn't in this case.

Both const and non-const version of the same function - an anti-pattern?

No, not always.

There are legitimate uses for this pattern. For example, suppose you are writing a collection, and the code for retrieving an element is fairly complex (e.g. a hash table). You don't want to duplicate all the code, but you also want your collection to be able to be used as both const and non-const.

So, you might do something like this:

struct HashTable {
...

const Value &get(Key key) const {
... complex code for retrieving the key
}

Value &get(Key key) {
return const_cast<Value &>(
static_cast<const HashTable *>(this)->get(key)
);
}
};

Here, the const_cast<> is not really a lie. Since your function is non-const, you know that it can be called only if the object pointed to by this is also non-const. Hence, casting the constness away is valid.

(of course, similarly to this situation, you can call a non-const method by casting away the const-ness of a const instance, but at that point its the user of your class who has already introduced undefined behavior, so you are covered as long as your class is being used correctly.)

Calling a const function from a non-const object

Avoid the cast: assign this to a const Bar * or whatever and use that to call getProcess().

There are some pedantic reasons to do that, but it also makes it more obvious what you are doing without forcing the compiler to do something potentially unsafe. Granted, you may never hit those cases, but you might as well write something that doesn't use a cast in this case.



Related Topics



Leave a reply



Submit