What does const_forward do in an optional C ++ implementation?
Hey. I am considering one of the implementations std::optional
here in here and I found this piece of code confusing me:
// workaround: std utility functions aren't constexpr yet
template <class T> inline constexpr T&& constexpr_forward(typename
std::remove_reference<T>::type& t) noexcept
{
return static_cast<T&&>(t);
}
So I don't understand it this way:
- What's doing here
typename
? Just declaring the next part - is this a type? - Why do we need it
std::remove_reference
here? Didn't we add the link back to the parttype&
? - What does "std utility functions not constexpr yet" mean? How does this function make them constexpr? His body is only
static_cast
. - This function is used in several constructors and looks like this:
template <class... Args> constexpr storage_t( Args&&... args ) : value_(constexpr_forward<Args>(args)...) {}
so what does it do here for arguments?
Many thanks.
source to share
template <class T> inline constexpr T&& constexpr_forward(typename
std::remove_reference<T>::type& t) noexcept
{
return static_cast<T&&>(t);
}
- What's doing
typename
here? Just declaring the next part - is this a type?
std::remove_reference<T>::type
is a dependent type that depends on a template parameter T
, so we need to typename
tell the compiler that we are trying to use a dependent name ,
- Why do we need it
std::remove_reference
here? Didn't we add the link back to the parttype&
?
If you see an example of using this utility function like in here
....
template <class... Args> explicit constexpr constexpr_optional_base(in_place_t, Args&&... args)
: init_(true), storage_(constexpr_forward<Args>(args)...) {}
...
You can see that the constexpr_foward<Args>(args)...
variable reference reference type is used as the explicit template argument for . This will preserve the category of values ββof that type. If any of the arguments are a reference, it will be as if we had called this utility function with constexpr_forward<Arg01&>(arg01)
. And the instatiation of this template would be
inline constexpr Arg01&&& constexpr_forward(Arg01& t) noexcept
{
return static_cast<Arg01&&&>(t);
}
and the link folding rule , we have
inline constexpr Arg01& constexpr_forward(Arg01& t) noexcept
{
return static_cast<Arg01&>(t);
}
Actually, the link to delete should be superfluous there (read about link folding);
- What does "std utility functions not constexpr yet" mean? How does this function make them constexpr? His body is only
static_cast
.
It does nothing more than function forwardingconstexpr
in constexpr
functions and constructors.
- This function is used in several constructors and looks like this:
template <class... Args> constexpr storage_t( Args&&... args ) : value_(constexpr_forward<Args>(args)...) {}
so what does it do here for arguments?
Basically as described above.
source to share
You may need to go back to step and do a few more reads, this code is quite advanced and your questions indicate that you have not read some of this material. I would recommend Modern Effective C ++ to Scott Meyers. As for your specific questions:
- Yes, it should be used
typename
because we are dealing with a member of a template class, which is a dependent type. Think of it as the compiler assuring that the thing is indeed a type the moment the compiler can check it (since the template was not created, it is defined, so it doesn't know what it isT
). - Unlike most template functions, the idea behind
std::forward
is to explicitly specify the template parameter to make it work correctly. This form disables type inference, which is desirable in this context (rarely). Note that removing a link and adding it back is not the same as doing nothing, as if it's not a link to start with, it still ends up as one. This is the goal; to always take an lvalue reference. - It simply means that they are unchecked
constexpr
. The function can be used in constant expressions if it is checkedconstexpr
. Not all functions can be checkedconstexpr
, there are limitations. A standard library functionstd::forward
may be constexpr, but it just isn't. This feature is just a workaround for this. - This is mostly equivalent
std::forward
, so it would be nice to talk about it and read about it, as it is not a trivial thing to search for (and the book I mentioned talks about it). Basically the idea is that once you have a function that takes a set of arguments, suppose it wants to forward those arguments elsewhere. The point is that all symbol names (in this case,args
) are considered lvalues ββ(although they are rvalue references ... as I said, this is confusing, put vs value category). However, if the user has gone through any time periods, we want him to be correctly redirected (i.e. Temporarily) to the next function.std::forward
ensures that things are passed as rvalues, returned in rvalue references, and can be used correctly by an internal function.
Hope this helps. Again, you will need to spend some time reading to gain a deeper understanding of value categories and reference rvalues ββto fully digest it.
source to share