aboutsummaryrefslogtreecommitdiffhomepage
path: root/development/c++
diff options
context:
space:
mode:
authorjohannst <johannst@users.noreply.github.com>2023-05-29 20:34:16 +0000
committerjohannst <johannst@users.noreply.github.com>2023-05-29 20:34:16 +0000
commiteaad036407c9546be0de27f61745fef4b6856e56 (patch)
treec270e3fbc87f3b7c9fc25ac60f4f8f611962de5e /development/c++
parent87c538b89ea68cf0c133a9243097ffac646e6739 (diff)
downloadnotes-eaad036407c9546be0de27f61745fef4b6856e56.tar.gz
notes-eaad036407c9546be0de27f61745fef4b6856e56.zip
deploy: d2013ee5952bbcf88906a832748783e372f3a939
Diffstat (limited to 'development/c++')
-rw-r--r--development/c++/.clang-format2
-rw-r--r--development/c++/Makefile2
-rw-r--r--development/c++/fwd-perfect.cc82
-rw-r--r--development/c++/fwd.cc58
-rw-r--r--development/c++/meta2.cc12
-rw-r--r--development/c++/meta4.cc4
6 files changed, 154 insertions, 6 deletions
diff --git a/development/c++/.clang-format b/development/c++/.clang-format
index 3cfb373..1b5900c 100644
--- a/development/c++/.clang-format
+++ b/development/c++/.clang-format
@@ -18,7 +18,7 @@ AllowAllConstructorInitializersOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortBlocksOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: false
-AllowShortFunctionsOnASingleLine: Inline
+AllowShortFunctionsOnASingleLine: Empty
AllowShortIfStatementsOnASingleLine: Never
AllowShortLambdasOnASingleLine: All
AllowShortLoopsOnASingleLine: false
diff --git a/development/c++/Makefile b/development/c++/Makefile
index ca752d9..622bfd3 100644
--- a/development/c++/Makefile
+++ b/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 fwd-perfect.cc
BIN = $(SRC:.cc=)
all: $(BIN)
diff --git a/development/c++/fwd-perfect.cc b/development/c++/fwd-perfect.cc
new file mode 100644
index 0000000..2fafc3e
--- /dev/null
+++ b/development/c++/fwd-perfect.cc
@@ -0,0 +1,82 @@
+// Copyright (C) 2023 johannst
+
+#include <cassert>
+#include <cstdio>
+#include <new>
+#include <type_traits>
+#include <utility>
+
+struct S {};
+
+struct M {
+ M() {
+ std::puts("M()");
+ }
+ M(const M&) {
+ std::puts("M(M&)");
+ }
+ M(M&&) {
+ std::puts("M(M&&)");
+ }
+ M& operator=(const M&) = delete;
+ M& operator=(M&&) = delete;
+
+ M(S&, int) {
+ std::puts("M(S&)");
+ }
+ M(S&&, int) {
+ std::puts("M(S&&)");
+ }
+ ~M() {
+ std::puts("~M()");
+ }
+};
+
+template<typename T>
+struct option {
+ static_assert(!std::is_reference_v<T>);
+
+ constexpr option() = default;
+
+ template<typename... Params>
+ constexpr option(Params&&... params) : m_has_val(true) {
+ // BAD: does not perfectly forward!
+ // eg, if option(S&&) is invoked, this would invoke M(S&).
+ // new (&m_val) T(params...);
+
+ // GOOD: perfectly forwards params to constructor of T.
+ new (m_val) T(std::forward<Params>(params)...);
+ }
+
+ ~option() {
+ reset();
+ }
+
+ constexpr T& value() {
+ assert(m_has_val);
+ return *reinterpret_cast<T*>(m_val);
+ }
+
+ private:
+ constexpr void reset() {
+ if (!m_has_val) {
+ return;
+ }
+ if constexpr (!std::is_trivially_destructible_v<T>) {
+ value().~T();
+ };
+ }
+
+ alignas(T) char m_val[sizeof(T)];
+ bool m_has_val{false};
+};
+
+int main() {
+ std::puts("==> case 1");
+ // invokes M(S&&, int)
+ option<M> opt1(S{}, 123);
+
+ std::puts("==> case 2");
+ // invokes M() + M(M&&)
+ option<M> x /* option(M&&) + M(M&&) */ = M{} /* M() */;
+}
diff --git a/development/c++/fwd.cc b/development/c++/fwd.cc
new file mode 100644
index 0000000..802d5bb
--- /dev/null
+++ b/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&).
+ }
+}
diff --git a/development/c++/meta2.cc b/development/c++/meta2.cc
index 4c1194f..cd9c625 100644
--- a/development/c++/meta2.cc
+++ b/development/c++/meta2.cc
@@ -52,7 +52,9 @@ void Invoke(const Ctx& C, P... params) {
// Custom context.
struct Ctx {
- void out(const char* s, unsigned v) const { printf("%s%x\n", s, v); }
+ void out(const char* s, unsigned v) const {
+ printf("%s%x\n", s, v);
+ }
};
// Operations to invoke.
@@ -63,7 +65,9 @@ struct OpA {
using Return = int;
static constexpr const char* const Name = "OpA";
- constexpr Return operator()(int a, int b) const { return a + b; }
+ constexpr Return operator()(int a, int b) const {
+ return a + b;
+ }
};
template<typename Ctx>
@@ -72,7 +76,9 @@ struct OpB {
using Return = void;
static constexpr const char* const Name = "OpB";
- Return operator()(const Ctx& C, unsigned a) const { C.out("a = ", a); }
+ Return operator()(const Ctx& C, unsigned a) const {
+ C.out("a = ", a);
+ }
};
int main() {
diff --git a/development/c++/meta4.cc b/development/c++/meta4.cc
index 9c3be77..7437cb4 100644
--- a/development/c++/meta4.cc
+++ b/development/c++/meta4.cc
@@ -22,7 +22,9 @@ struct registry {
return r.second;
}
- R invoke(const std::string& nm, P... p) const { return invoke_impl<R>(nm, p...); }
+ R invoke(const std::string& nm, P... p) const {
+ return invoke_impl<R>(nm, p...);
+ }
void dump() const {
for (const auto& it : m_fns) {