diff options
author | Johannes Stoelp <johannes.stoelp@gmail.com> | 2023-05-28 22:44:16 +0200 |
---|---|---|
committer | Johannes Stoelp <johannes.stoelp@gmail.com> | 2023-05-28 23:13:04 +0200 |
commit | 80fa1be3da1b5a20042eccd04df57b01a30a7744 (patch) | |
tree | d55df72dd0e7647bd6dd99592ebfca12a7039f80 | |
parent | 2b0c34c8d13ab4a899a722ae272a366bf6051168 (diff) | |
download | notes-80fa1be3da1b5a20042eccd04df57b01a30a7744.tar.gz notes-80fa1be3da1b5a20042eccd04df57b01a30a7744.zip |
c++: fwd referene + perfect fwd
-rw-r--r-- | src/development/c++.md | 26 | ||||
-rw-r--r-- | src/development/c++/Makefile | 2 | ||||
-rw-r--r-- | src/development/c++/fwd.cc | 58 |
3 files changed, 85 insertions, 1 deletions
diff --git a/src/development/c++.md b/src/development/c++.md index 6cdc251..655a603 100644 --- a/src/development/c++.md +++ b/src/development/c++.md @@ -1,5 +1,7 @@ # c++ +Source files of most examples is available [here][src-examples]. + ## Type deduction Force compile error to see what `auto` is deduced to. @@ -16,6 +18,27 @@ typename decltype(foo)::_; {{#include c++/meta.cc:3:}} ``` +## Forwarding reference ([fwd ref][fwd-ref]) + +A `forwarding reference` is a special references that preserves the `value +category` of a function parameter and therefore allows for `perfect` +forwarding. + +A forwarding reference is a parameter of a function template, which is declared +as `rvalue` reference to a `non-cv` qualified `type` template parameter. +```cpp +template<typename T> +void fn(T&& param); // param is a forwarding reference +``` + +Perfect forwarding can be achieved with [`std::forward`][std-fwd]. This for +example allows a wrapper function to pass a parameter with the **exact** same +value category to a down-stream function which is being invoked in the wrapper. + +```cpp +{{#include c++/fwd.cc:3:}} +``` + ## Example: `any_of` template meta function ```cpp @@ -74,3 +97,6 @@ A more detailed description is available in the SO discussion [How does [parameter-pack]: https://en.cppreference.com/w/cpp/language/parameter_pack [enable-if]: https://en.cppreference.com/w/cpp/types/enable_if [sfinae]: https://en.cppreference.com/w/cpp/language/sfinae +[fwd-ref]: https://en.cppreference.com/w/cpp/language/reference#Forwarding_references +[std-fwd]: https://en.cppreference.com/w/cpp/utility/forward +[src-examples]: https://github.com/johannst/notes/tree/master/src/development/c%2B%2B diff --git a/src/development/c++/Makefile b/src/development/c++/Makefile index ca752d9..36065e4 100644 --- a/src/development/c++/Makefile +++ b/src/development/c++/Makefile @@ -1,4 +1,4 @@ -SRC = concepts-11.cc meta.cc meta2.cc meta4.cc tmpl-pair.cc tmpl-void_t.cc +SRC = concepts-11.cc meta.cc meta2.cc meta4.cc tmpl-pair.cc tmpl-void_t.cc fwd.cc BIN = $(SRC:.cc=) all: $(BIN) diff --git a/src/development/c++/fwd.cc b/src/development/c++/fwd.cc new file mode 100644 index 0000000..802d5bb --- /dev/null +++ b/src/development/c++/fwd.cc @@ -0,0 +1,58 @@ +// Copyright (C) 2023 johannst + +#include <cstdio> +#include <utility> + +struct M {}; + +// -- CONSUMER ----------------------------------------------------------------- + +void use(M&) { + puts(__PRETTY_FUNCTION__); +} + +void use(M&&) { + puts(__PRETTY_FUNCTION__); +} + +// -- TESTER ------------------------------------------------------------------- + +template<typename T> +void wrapper(T&& param) { // forwarding reference + puts(__PRETTY_FUNCTION__); + // PARAM is an lvalue, therefore this always calls use(M&). + use(param); +} + +template<typename T> +void fwd_wrapper(T&& param) { // forwarding reference + puts(__PRETTY_FUNCTION__); + // PARAM is an lvalue, but std::forward returns PARAM with the same value + // category as the forwarding reference takes. + use(std::forward<T>(param)); +} + +// -- MAIN --------------------------------------------------------------------- + +int main() { + { + std::puts("==> wrapper rvalue reference"); + wrapper(M{}); + // calls use(M&). + + std::puts("==> wrapper lvalue reference"); + struct M m; + wrapper(m); + // calls use(M&). + } + { + std::puts("==> fwd_wrapper rvalue reference"); + fwd_wrapper(M{}); + // calls use(M&&). + + std::puts("==> fwd_wrapper lvalue reference"); + struct M m; + fwd_wrapper(m); + // calls use(M&). + } +} |