I've recently been looking into forwarding references in C++ and below is a quick summary of my current understanding of the concept.
Let's say I have a template function foo
taking a forwarding reference to a single argument of type T
.
template<typename T>
void foo(T&& arg);
If I call this function with an lvalue then T
will be deduced as T&
making the arg
parameter be of type T&
due to the reference collapsing rules T& && -> T&
.
If this function gets called with an unnamed temporary, such as the result of a function call, then T
will be deduced as T
making the arg
parameter be of type T&&
.
Inside foo
however, arg
is a named parameter so I will need to use std::forward
if I want to pass the parameter along to other functions and still maintain its value category.
template<typename T>
void foo(T&& arg)
{
bar(std::forward<T>(arg));
}
As far as I understand the cv-qualifiers are unaffected by this forwarding. This means that if I call foo with a named const variable then T
will be deduced as const T&
and hence the type of arg
will also be const T&
due to the reference collapsing rules. For const rvalues T
will be deduced as const T
and hence arg
will be of type const T&&
.
This also means that if I modify the value of arg
inside foo
I will get a compile time error if I did infact pass a const variable to it.
Now onto my question. Assume I am writing a container class and want to provide a method for inserting objects into my container.
template<typename T>
class Container
{
public:
void insert(T&& obj) { storage[size++] = std::forward<T>(obj); }
private:
T *storage;
std::size_t size;
/* ... */
};
By making the insert
member function take a forwarding reference to obj
I can use std::forward
to take advantage of the move assignment operator of the stored type T
if insert
was infact passed a temporary object.
Previously, when I didn't know anything about forwarding references I would have written this member function taking a const lvalue reference: void insert(const T& obj)
.
The downside of this is that this code does not take advantage of the (presumably more efficient) move assignment operator if insert
was passed a temporary object.
Assuming I haven't missed anything.
Is there any reason to provide two overloads for the insert function? One taking a const lvalue reference and one taking a forwarding reference.
void insert(const T& obj);
void insert(T&& obj);
The reason I'm asking is that the reference documentation for std::vector
states that the push_back
method comes in two overloads.
void push_back (const value_type& val);
void push_back (value_type&& val);
Why is the first version (taking a const value_type&
) needed?
Aucun commentaire:
Enregistrer un commentaire