Nayana Adassuriya
Nayana Adassuriya

Reputation: 24766

Behavior of function overloading with const

I'm working on g++ and here I have tried to overload a function by just adding const to parameter. It works fine and when it runs, it calls the function without const

  1. Is this behavior specified in the C++ standard?
  2. What the reason it calls the function without const

    void print(const std::string& str){std::cout << "const" << str << std::endl;}
    
    void print(std::string& str){std::cout << str << std::endl;}
    
    int main()
    {
       std::string temp = "hello";
       print(temp);
       return 0;
    }
    

Upvotes: 3

Views: 98

Answers (6)

Clifford
Clifford

Reputation: 93466

Overloading works by matching the types of the arguments, including the qualifiers. In your case temp has type std::string not const std::string. You have only initialised it with a literal constant, it is not itself constant.

Consider the following:

std::string temp( "hello" ) ;
print(temp);                                    // hello   
print( std::string("hello") ) ;                 // consthello
print( "hello" ) ;                              // consthello
print( static_cast<const std::string>(temp) ) ; // consthello

const std::string temp2( "hello" ) ;
print(temp2);                                    // consthello   

If you were to remove the non-const version, all three will call the remaining const overload. In this example, only the const version is in fact necessary (and preferred) since neither version modify the string object.

If on the other hand you removed the non-const version, there would be no function matching any but the first example above, and the build would fail. That is to say a non-const object can safely be passed as a const argument, but a const object cannot be passed as a non-const argument, because the function is not "promising" not to modify the object. You can force a const into a non-const argument by a const_cast as in:

const std::string temp2("hello") ;
print( const_cast<std::string&>(temp2) ) ;    // hello

But if print() were to attempt to modify the object in this case the results are undefined, so consider the practice unsafe.

Making an argument const indicates intent, allows the compiler to issue a diagnostic if the code is attempts to modify the object or pass it via a non-const argument to some other function. It may also potentially provide the compiler with optimisation possibilities.

Upvotes: 1

Columbo
Columbo

Reputation: 60979

The reason is this section in [over.ics.rank]/3 where this case is explicitly covered:

Standard conversion sequence S1 is a better conversion sequence than standard conversion sequence S2 if
[…]
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.

S1 corresponds to the second overload and S2 to the first.

What the reason it calls the function without const

You always try to select the most specialized thing. That is the case in overload resolution just as it is in partial ordering of function templates. The second overload is more specialized than the first because the first can be called with arguments which the second cannot be called with - that is the basic reasoning behind this rule.

Upvotes: 1

Marco A.
Marco A.

Reputation: 43662

Reference bindings are an identity category §13.3.3.1.4) but since the latter is more cv-qualified, for §13.3.3.2, the non-const is preferred (sample code from the standard):

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

int i;
int j = f(i); // calls f(int &)

Upvotes: 2

Vladimir Fedosov
Vladimir Fedosov

Reputation: 102

const is part of method signature. Overriding works only for methods with the same signature. This behavior was made to avoid reverse situation when you use const method of base class to call not const method of child class.

Upvotes: 1

Ben
Ben

Reputation: 9703

That is standard behavior. Any other behavior would lead to crazy behavior. In particular, the non-const function would not be callable at all.

Upvotes: 1

user1804599
user1804599

Reputation:

Because calling the function taking std::string const& requires two implicit conversions: one to std::string const, one to std::string const&; whereas calling the function taking std::string& requires merely one implicit conversion (to std::string&), so that one is preferred.

Upvotes: 0

Related Questions