diff options
author | johannst <johannst@users.noreply.github.com> | 2023-05-29 20:34:16 +0000 |
---|---|---|
committer | johannst <johannst@users.noreply.github.com> | 2023-05-29 20:34:16 +0000 |
commit | eaad036407c9546be0de27f61745fef4b6856e56 (patch) | |
tree | c270e3fbc87f3b7c9fc25ac60f4f8f611962de5e /development/c++ | |
parent | 87c538b89ea68cf0c133a9243097ffac646e6739 (diff) | |
download | notes-eaad036407c9546be0de27f61745fef4b6856e56.tar.gz notes-eaad036407c9546be0de27f61745fef4b6856e56.zip |
deploy: d2013ee5952bbcf88906a832748783e372f3a939
Diffstat (limited to 'development/c++')
-rw-r--r-- | development/c++/.clang-format | 2 | ||||
-rw-r--r-- | development/c++/Makefile | 2 | ||||
-rw-r--r-- | development/c++/fwd-perfect.cc | 82 | ||||
-rw-r--r-- | development/c++/fwd.cc | 58 | ||||
-rw-r--r-- | development/c++/meta2.cc | 12 | ||||
-rw-r--r-- | development/c++/meta4.cc | 4 |
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) { |