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 part type&

    ?
  • 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.

+3


source to share


2 answers


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 ,

  1. Why do we need it std::remove_reference

    here? Didn't we add the link back to the part type&

    ?

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);

  1. 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.

  1. 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.

+5


source


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 is T

    ).
  • 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 checked constexpr

    . Not all functions can be checked constexpr

    , there are limitations. A standard library function std::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.

+2


source







All Articles