6

I have overloaded const and non-const functions in c++ structure. Then, I have run the program and I wondered, it's working fine without ambiguous error.

#include <iostream>

struct St 
{
  int f() const 
  { 
      return 1; 
  }

  int f()
  { 
      return 2;
  }
} s;

int main() 
{
    int ret = s.f();  
    std::cout<<ret<<std::endl;
    return 0;
}

So, I just want to know, Why doesn't the compiler give an ambiguous error for "const" and "not-const" functions?

msc
  • 33,420
  • 29
  • 119
  • 214
  • [duplicate] https://stackoverflow.com/questions/856542/elegant-solution-to-duplicate-const-and-non-const-getters – Nidhi257 Oct 05 '17 at 06:22
  • 2
    Possible duplicate of [Meaning of "const" last in a C++ method declaration?](https://stackoverflow.com/questions/751681/meaning-of-const-last-in-a-c-method-declaration) – Jim Lewis Oct 05 '17 at 06:24

3 Answers3

4

First an informal explanation

Let's take it in logical steps.

A non-const method is allowed and assumed to change the object. As such it can be called on non-const objects only.

A const method is not allowed to change the object. As such it can be called on const objects, but also on non-const objects.

When both overloads of a functions are defined (const and non-const) the method chosen is the one whose constness fits the object constness.

The standard

In reality overload resolution has no special rule for const and non-const methods. Instead, the standard specifies an implicit object parameter. After you take into consideration this implicit object parameter, you can apply the usual overload resolution rules:

§13.3.1 Candidate functions and argument lists [over.match.funcs]

  1. [...] a member function is considered to have an extra parameter, called the implicit object parameter , which represents the object for which the member function has been called. For the purposes of overload resolution, both static and non-static member functions have an implicit object parameter, but constructors do not.

  2. Similarly, when appropriate, the context can construct an argument list that contains an implied object argument to denote the object to be operated on. Since arguments and parameters are associated by position within their respective lists, the convention is that the implicit object parameter, if present, is always the first parameter and the implied object argument, if present, is always the first argument.

  3. For non-static member functions, the type of the implicit object parameter is

    • (4.1) “lvalue reference to cv X” for functions declared without a ref-qualifier or with the & ref-qualifier
    • (4.2) “rvalue reference to cv X” for functions declared with the && ref-qualifier

where X is the class of which the function is a member and cv is the cv-qualification on the member function declaration. [ Example: for a const member function of class X, the extra parameter is assumed to have type “reference to const X”. —end example ] For conversion functions, the function is considered to be a member of the class of the implied object argument for the purpose of defining the type of the implicit object parameter. For non-conversion functions introduced by a using-declaration into a derived class, the function is considered to be a member of the derived class for the purpose of defining the type of the implicit object parameter. [...]

  1. During overload resolution, the implied object argument is indistinguishable from other arguments
bolov
  • 72,283
  • 15
  • 145
  • 224
4

This is const overloading, which is a thing in C++.

In this case, the compiler determines the struct does NOT have an overloaded function return type, (which is disallowed due to ambiguity of course) but rather an overloaded function with different “constness;” a term in one of the other answers which makes sense here.

As for getting no compiler errors:

  1. const overloading is part of the C++ specification, so no errors
  2. At compile-time, the compiler “sees” that the struct is returning to a non-const environment, so uses the non-const function, causing a normal operation to happen

Hope that helps!

NonCreature0714
  • 5,744
  • 10
  • 30
  • 52
2

Assume that every member function of class A has an implicit parameter that is const A& for a const member function and A& for a non-const member function. Your member functions in the context of overload resolution process will look like:

int f(const St&); 
int f(St&);

If it is possible for overload resolution to choose the appropriate member than there is no ambiguity. This specific case is regulated in

13.3.3.2 [over.ics.rank] Standard conversion sequence S1 is a better conversion sequence than standard conversion sequence S2 if
...
13.3.3.2/(3.2.6) S1 and S2 are reference bindings, and the types to which the references refer are the same type except for top-level cv-qualifiers, and the type to which the reference initialized by S2 refers is more cv-qualified than the type to which the reference initialized by S1 refers.

Thus, overload resolution process chooses the non-const member (as less cv-qualified).

DAle
  • 8,990
  • 2
  • 26
  • 45
  • Technically this isn't a qualification conversion (that term refers to non-top-level qualification changes); the rule in C++14 is [over.ics.rank]/3.1.6 "S1 and S2 are reference bindings (8.5.3), and the types to which the references refer are the same type except for top-level cv-qualifiers, and the type to which the reference initialized by S2 refers is more cv-qualified than the type to which the reference initialized by S1 refers." – M.M Oct 05 '17 at 08:10
  • @M.M, Thanks! Added to the answer – DAle Oct 05 '17 at 09:19