Function overloading behavior with const

I am working on g ++ and here I tried to overload a function by simply adding a parameter const

to a parameter. It works fine and when it starts it calls the function withoutconst

  • Is this behavior specified in the C ++ standard?
  • What is 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;
    }
    
          

+3


source to share


6 answers


Bindings are an identity category of ยง13.3.3.1.4), but since the latter is more qualified, non-const is preferred for ยง13.3.3.2 (example code from the standard):



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

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

      

+3


source


This is standard behavior. Any other behavior will lead to crazy behavior. In particular, a non-const function will not be called at all.



+1


source


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

+1


source


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

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 of the same type, except for the top-level cv qualifiers , and of the type to which the character-initialized reference S2

has more CV than the type to which the character-initialized reference belongs S1

.

S1

corresponds to the second overload, and S2

- to the first.

What is the reason it calls the function without const

You always try to choose the most specialized thing. This is the case with overload resolution in the same way as with partial ordering of function templates. The second overload is more specialized than the first, because the first can be called with arguments that the second cannot be called โ€” that's the main reason for this rule.

+1


source


Overloading is done by matching the types of the arguments, including qualifiers. In your case, it temp

is of type std::string

not const std::string

. You only initialized it with a literal constant, it is not a 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 want to remove the non-constant version, all three will invoke the remaining constant overload. In this example, only the const version is actually needed (and preferably) since neither version modifies the string object.

If, on the other hand, you removed the non-const version, there was no function matching any other than the first example above, and the build failed. That is, a non-const object can be safely passed as a const argument, but a const object cannot be passed as a non-const argument, because the function does not "promise" not to modify the object. You can force const to a non-const argument with const_cast

, as in:

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

      

But if print()

tried to modify the object, in that case the results are undefined, so consider practice as unsafe.

Creating a const argument indicates intent, allows the compiler to issue diagnostics if code tries to modify an object or pass it using a non-const argument to some other function. It can also potentially provide optimization opportunities for the compiler.

+1


source


Because calling a function that accepts std::string const&

requires two implicit conversions: one to std::string const

, one to std::string const&

; whereas calling the accepting function std::string&

requires only one implicit conversion (to std::string&

), so that's preferable.

0


source







All Articles