Reputation: 24766
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
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
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
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 sequenceS2
if
[…]
—S1
andS2
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 byS2
refers is more cv-qualified than the type to which the reference initialized byS1
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
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
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
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
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