aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorJohannes Stoelp <johannes.stoelp@gmail.com>2023-05-28 22:44:16 +0200
committerJohannes Stoelp <johannes.stoelp@gmail.com>2023-05-28 23:13:04 +0200
commit80fa1be3da1b5a20042eccd04df57b01a30a7744 (patch)
treed55df72dd0e7647bd6dd99592ebfca12a7039f80 /src
parent2b0c34c8d13ab4a899a722ae272a366bf6051168 (diff)
downloadnotes-80fa1be3da1b5a20042eccd04df57b01a30a7744.tar.gz
notes-80fa1be3da1b5a20042eccd04df57b01a30a7744.zip
c++: fwd referene + perfect fwd
Diffstat (limited to 'src')
-rw-r--r--src/development/c++.md26
-rw-r--r--src/development/c++/Makefile2
-rw-r--r--src/development/c++/fwd.cc58
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&).
+ }
+}