I've made the argument to a function const& because I want to be able to pass "string literals" to it.
If you're interested, the exact type of a string literal like this...
"string literal"
... is const char[15]
. It just so happens that a std::string
has a constructor that takes const char*
, which const char[15]
automatically decays to, so a string literal binds to a const std::string&
parameter.
(const char[15]) --> decay --> (const char*) --> bind --> std::string::string( const char* )
This creates a temporary std::string
, which holds a copy of the string literal. Your function then takes that temporary std::string
as a const std::string&
. The original temporary is not actually const
Whether or not the original temporary is const
is wishy-washy in the standard apparently, but it is const
in C++17, according to the other answer.
However I'm wondering whether it's possible to modify the reference
I'm wondering whether casting away the const on the std::string reference is undefined.
If you want to modify the temporary, there's no need for const_cast
. The language gives you a way to bind to temporaries in a non-const
way: the rvalue
reference.
// this is a const lvalue reference
// it binds to temporaries
void addObjectToDictionary(int* obj, const std::string& name);
// this is an rvalue reference
// it also binds to temporaries, and will bind to temporaries instead of a
// const lvalue reference if both overloads exist
void addObjectToDictionary(int* obj, std::string&& name);
The answer to your stated question...
I'd just like to know, however, whether the temporary std::string object created when calling the function is considered const or not.
... is no, temporaries are not const
apparently yes for C++17 according to the other answer. However, y You should also not take a temporary by const
lvalue reference and cast the const
away, because that signature also binds to actually const
objects. Instead, you can bind to a temporary in a non-const
way using an rvalue
reference parameter.
As a bonus, if you want to bind directly to a string literal, you can do this:
// this templates functions that bind to the exact type of any string literal
template<std::size_t N>
void addObjectToDictionary(int* obj, const char ( &name )[N] );
This template generates functions that bind to the exact types of string literals of any length. This may be a little overboard.
EDIT
There's a suggestion in the comments to take the string by value (std::string
, no reference). This is also a perfectly valid way to "sink" a string into your function.
// this will bind to string literals without creating a temporary
void addObjectToDictionary(int* obj, std::string name);
What happens here, then, is a bit different. When passing a string literal to a const std::string&
parameter, you get a const
reference to a temporary std::string
. When passing a string literal to a plain old std::string
value, what used to be a temporary is now your very own std::string
value object to do with as you wish, constructed from the string literal.