问题
I asked a related, tedious question before and now I discover something new.
#include <iostream>
#include <string>
using namespace std;
void hello (const string &s1) {
cout << "rocky" << endl;
}
void hello(string &s1) {
cout << "banana" << endl;
}
int main()
{
string s = "abc";
hello(const_cast<const string&>(s)); //how to explain this const_cast?
}
hello(const_cast<const string&>(s));
this works and match the const reference parameter function. So how's the conversion this time? Isn't it string
to const string&
?
Certainly I know that const reference can be initialized with non-const objects... But somehow I never take that as a conversion. I see it as an assignment. And I consider the type of reference and the type of referent as two very different stuff.
回答1:
Expressions, objects, variables - I know C++ can be a bit confusing to newcomers, especially when it comes to the subtle details.
So s
here is a variable in main
. While main
runs (and that's the whole program, since it's main
), there is an object that corresponds to the variable. And in main
, the expression s
refers to to that object. But there are many more expressions that refer to the same object. (s)
is another expression that refers to the same object. So is *&s
. Or *(&s)
.
s+""
is another expression that has the same value. But it's not the same object. Cf. integers i+0
or i*1
.
References can be used to define variables which introduce new names for objects, names that can then be used in expressions. There are many places where it's convenient to be able to explicitly name something. It's just a new name, not a new object.
const_cast
is another use for references. This however doesn't introduce a new name; it just forms a new expression with a const
added to the type.
Now to your hello
. This is an overloaded function. Overload resolution is done on the type of the expression used as an argument. So in hello(s1)
, s1
is the simple expression used for overload resolution, and its type is std::string
. In hello(const_cast<std::string const&>(s1))
, the expression is const_cast<std::string const&>(s1)
, and its type is obviously std::string const&
.
Both expressions refer to the same object; they only differ in type. But that type difference is exactly what overload resolution needs.
回答2:
You can only convert from const reference to lvalue reference explicitly by using const_cast
as such conversion is not safe and must be explicit. On another side you can convert from lvalue or lvalue reference to const reference implicitly or explicitly, as such conversion is safe. So usually nobody cast to const reference explicitly as it is unnecessary verbose and does not make sense. In your case it is converted explicitly to select certain overloaded function, because compiler would not convert it implicitly, as it can find overload with lvalue reference, but your example is rather artificial, as it is difficult to imagine why somebody would have such overload.
回答3:
So, primary meaning for the cast is to pick necessary one from the list of overloaded hello() functions. Without the cast, we pick non-const version, otherwise it's const one.
Secondly, why the cast of the string reference, not just string type? This is due limitations of the const_cast itself. Let's try to compile that:
hello(const_cast<const string>(s)); // we removed the "&"
compiler message:
error: invalid use of const_cast with type ‘const string {aka const std::__cxx11::basic_string<char>}’,
which is not a pointer, reference, nor a pointer-to-data-member type
So, const_cast is not intended to create new instance, instead it works with indirection to given instance and just changes associated CV qualification (as it's free lunch in terms of code generation). So, we have to deal with a pointer or reference to conform that condition.
P.S. As far as I know, C++17 allows creation of temporary copies for the casting (aka Temporary materialization) so our non-ref attempt could have practical meaning. Same time, it's quite new concept and not so wide-spread.
来源:https://stackoverflow.com/questions/49800593/how-can-const-castconst-string-s-while-s-is-a-string-type