I would assume
std::optional<const std::string>
allows to assign a new value to the optional, but it is not possible to change the string itself and in
const std::optional<const std::string>
it is not possible to do both. But what about the following?
const std::optional<std::string>
No. A reference is simply an alias for an existing object. const is enforced by the compiler; it simply checks that you don't attempt to modify the object through the reference r .
When you call the function and pass an instance of T, an optional will be constructed which will own its own copy of T, therefore it will call T's copy constructor. In order to be able to call foo and pass a T without creating a copy, you can declare foo as receiving an optional reference, i.e.
(since C++17) The class template std::optional manages an optional contained value, i.e. a value that may or may not be present. A common use case for optional is the return value of a function that may fail.
C++ has in its definition a way to represent a sequence of characters as an object of the class. This class is called std:: string. String class stores the characters as a sequence of bytes with the functionality of allowing access to the single-byte character.
Let's do some testing then:
#include <string>
#include <optional>
int main() {
using n_c = std::optional<const std::string>;
using c_n = const std::optional<std::string>;
using n_n = std::optional<std::string>;
n_c opt_n_c{"a"};
c_n opt_c_n{"a"};
n_n opt_n_n{"a"};
opt_n_c.emplace("b");
// opt_c_n.emplace("b");
opt_n_n.emplace("b");
// opt_n_c->pop_back();
// opt_c_n->pop_back();
opt_n_n->pop_back();
}
The commented out lines do not work.
Think of it like this: A non-const std::optional<T>
can have no value or a T
, which can be replaced (Not using T::operator=
, just destructing the currently held T
if it exists and constructing a new one). A non-const std::optional<const T>
can do exactly the same, though const T
probably doesn't have an operator=
, so you can't mutate the held value, but you can still change what value is held. A const std::optional<T>
is also "logically const". If a const std::optional<T>
equals another const std::optional<T>
, and no non-const references are touched, they (should) always remain equal, so the held value (should) not be changed. This is why they return const-references to the held value, and is why const std::optional<T>
and const std::optional<const T>
are effectively the same.
But what about the following?
const std::optional<std::string>
Everything in the standard library is going to be const
-correct - so the accessors on optional
are all const
-qualified as appropriate. Calling value()
or operator*()
on a const optional<T>
is going to give you a const T&
(or const T&&
), never a T&
.
You have no direct access to a modifiable reference.
Note that if you had a const optional<int*>
, on the other hand, it's the pointer itself that is const
- not the pointee. So this is fine:
int i = 42;
const std::optional<int*> opt(&i);
*opt.value() = 57;
assert(i == 57);
Is the content of a
const std::optional
alwaysconst
?
Now technically, the above doesn't actually answer your question. A const std::optional<std::string>
does not hold a const std::string
- it holds a std::string
that it only exposes const
access to. So... technically... but really never do this seriously this is bad... this is well-defined:
const std::optional<std::string> opt("hello"s);
const_cast<std::string&>(opt.value()) = "I am a bad person and I feel bad"s;
Because the string
itself was never created as const
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With