Perfect forwarding

Perfect ForwardingPerfect Forwarding in C++Photo by Matt Walsh on UnsplashWhat is meant by perfect forwarding?“Forwarding” is the process where one function forwards its parameter to another function. When it is perfect, the function should receive the…


This content originally appeared on Level Up Coding - Medium and was authored by Pin Loon Lee

Perfect Forwarding

Perfect Forwarding in C++

cover
Photo by Matt Walsh on Unsplash

What is meant by perfect forwarding?

“Forwarding” is the process where one function forwards its parameter to another function. When it is perfect, the function should receive the same object passed from the function that does the forwarding.

In other words, perfect forwarding means we do not just forward objects, we also forward their salient properties, whether they are lvalues or rvalues, const or volatile.

Do not worry too much about the definition, we will go through some simple examples.

Let say we have a simple class as below

class Object {
public:
Object() = default;

void SetName(const std::string &name) { name_ = std::move(name); }
std::string GetName() const { return name_; }

private:
std::string name_;
};

We have also few overloaded functions named UseObject

void UseObject(Object &) {
std::cout << "calling UseObject(Object &)" << std::endl;
}

void UseObject(const Object &) {
std::cout << "calling UseObject(const Object &)" << std::endl;
}

void UseObject(Object &&) {
std::cout << "calling UseObject(Object &&)" << std::endl;
}

Now we have the main

int main() {
Object object;
const Object const_object;
UseObject(object);
UseObject(const_object);
UseObject(std::move(object));
}

which would produce the output as below

calling UseObject(Object &)
calling UseObject(const Object &)
calling UseObject(Object &&)

Right now, let’s say we have a simple template function that tries to pass the argument to UseObject function

template <typename T>
void NotForwardToUseObject(T x) {
UseObject(x);
}

Now, running of code

int main() {
Object object;
const Object const_object;
NotForwardToUseObject(object);
NotForwardToUseObject(const_object);
NotForwardToUseObject(std::move(object));
}

would result in

calling UseObject(Object &)
calling UseObject(Object &)
calling UseObject(Object &)

where functions are not called accordingly as what we have expected earlier.

This is due to the const and rvalueness being ignored by the template deduction for void NotForwardToUseObject(T x) .

To deal with reference parameters, we have to use universal references, because only universal reference parameters encode information about the lvalueness and rvalueness of the arguments that are passed to them.

Now if we use universal reference for template argument,

template <typename T>
void HalfForwardToUseObject(T &&x) { // universal reference
UseObject(x);
}

Running of code

int main() {
Object object;
const Object const_object;
HalfForwardToUseObject(object);
HalfForwardToUseObject(const_object);
HalfForwardToUseObject(std::move(object));
}

would result in

calling UseObject(Object &)
calling UseObject(const Object &)
calling UseObject(Object &)

Almost! Forwarding of const seems working but rvalueness of the argument still not getting forwarded correctly.

To have a true perfect forwarding, we have to cast x to its original type and lvalue- or r-value-ness

template <typename T>
void ForwardToUseObject(T &&x) {
UseObject(static_cast<T &&>(x));
}

Now, running of code

int main() {
Object object;
const Object const_object;
ForwardToUseObject(object);
ForwardToUseObject(const_object);
ForwardToUseObject(std::move(object));
}

would result in

calling UseObject(Object &)
calling UseObject(const Object &)
calling UseObject(Object &&)

Perfect! We have successfully passed the object properly. To simplify the code, we can use std::forward from C++ <utility> library,

template <typename T>
void PerfectForwardToUseObject(T &&x) {
UseObject(std::forward<T>(x));
}

I hope with the examples above, now you have understand what is meant by perfect forwarding. As usual, the code above is accessible from my github

Thanks for reading till the end of the post!


Perfect forwarding was originally published in Level Up Coding on Medium, where people are continuing the conversation by highlighting and responding to this story.


This content originally appeared on Level Up Coding - Medium and was authored by Pin Loon Lee


Print Share Comment Cite Upload Translate Updates
APA

Pin Loon Lee | Sciencx (2023-01-19T14:49:41+00:00) Perfect forwarding. Retrieved from https://www.scien.cx/2023/01/19/perfect-forwarding/

MLA
" » Perfect forwarding." Pin Loon Lee | Sciencx - Thursday January 19, 2023, https://www.scien.cx/2023/01/19/perfect-forwarding/
HARVARD
Pin Loon Lee | Sciencx Thursday January 19, 2023 » Perfect forwarding., viewed ,<https://www.scien.cx/2023/01/19/perfect-forwarding/>
VANCOUVER
Pin Loon Lee | Sciencx - » Perfect forwarding. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2023/01/19/perfect-forwarding/
CHICAGO
" » Perfect forwarding." Pin Loon Lee | Sciencx - Accessed . https://www.scien.cx/2023/01/19/perfect-forwarding/
IEEE
" » Perfect forwarding." Pin Loon Lee | Sciencx [Online]. Available: https://www.scien.cx/2023/01/19/perfect-forwarding/. [Accessed: ]
rf:citation
» Perfect forwarding | Pin Loon Lee | Sciencx | https://www.scien.cx/2023/01/19/perfect-forwarding/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.