Skip to content

Instantly share code, notes, and snippets.

@nthery
Last active May 20, 2022 15:29
Show Gist options
  • Save nthery/589885de47b41af177bfd2c6c22e729d to your computer and use it in GitHub Desktop.
Save nthery/589885de47b41af177bfd2c6c22e729d to your computer and use it in GitHub Desktop.
#include <utility>
struct Bar {
int *payload_;
Bar();
~Bar();
Bar(const Bar&);
Bar(Bar&&) noexcept;
Bar& operator=(const Bar&);
Bar& operator=(Bar&&) noexcept;
};
//////////////////////////////////////////////////////////////////////////////
// RVALUES AND LVALUES
// DISCLAIMER: WHAT FOLLOWS CONTAINS LIES BY OMISSION AND APPROXIMATION!
// For the purpose of this talk:
// lvalue: a named object used in an expression
Bar global_bar;
// rvalue: a call to a function returning by value
Bar build_bar();
//////////////////////////////////////////////////////////////////////////////
// REFERENCE FLAVORS
// References come in several flavors
// - non-const lvalue ref
// - const lvalue ref
// - rvalue ref
// - forwarding (aka universal) ref
// A non-const lvalue ref binds to lvalues only.
void test_non_const_lvalue_ref() {
[[maybe_unused]] Bar& r1 = global_bar;
// Bar& r2 = build_bar(); // compile error
}
// A const lvalue ref binds to lvalues and rvalues.
void test_const_lvalue_ref() {
[[maybe_unused]] Bar& r1 = global_bar;
[[maybe_unused]] const Bar& r3 = build_bar();
}
// An rvalue ref binds to rvalues only.
// Motivation for rvalues: move semantics
void test_rvalue_ref() {
// Bar&& r2 = global_bar; // compile error
[[maybe_unused]] Bar&& r1 = build_bar();
}
//////////////////////////////////////////////////////////////////////////////
// MOTIVATION FOR PERFECT FORWARDING
// perfect forwarding == forward without unneeded copies
void target(const Bar& x);
void target(Bar&& x);
// Let's use a const ref as they bind to both lvalues and rvalues.
template<class T>
void imperfect_forwarder(const T& x) {
// ...
target(x);
// ...
}
void test_imperfect_forwarder() {
// This calls target(const Bar&) :-)
imperfect_forwarder(global_bar);
// This calls target(const Bar&) which may cause a useless copy :-(
imperfect_forwarder(build_bar());
}
//////////////////////////////////////////////////////////////////////////////
// FORWARDING REFERENCES AND PERFECT FORWARDING
// A forwarding (aka universal) reference:
// - Preserves rvalues and lvalues
// - Looks syntactically like an rvalue ref but must follow the exact form below:
// - Parameter type is `T&&` (or `Ts...&&`)
// - T is a template parameter of the function
template<class T>
void perfect_forwarder(T&& x) {
// ...
target(std::forward<T>(x));
// ...
}
void test_perfect_fwd() {
// This calls target(const Bar&) :-)
perfect_forwarder(global_bar);
// This calls target(Bar&&), no redundant copies :-)
perfect_forwarder(build_bar());
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment