From eaad036407c9546be0de27f61745fef4b6856e56 Mon Sep 17 00:00:00 2001 From: johannst Date: Mon, 29 May 2023 20:34:16 +0000 Subject: deploy: d2013ee5952bbcf88906a832748783e372f3a939 --- development/c++/fwd-perfect.cc | 82 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 development/c++/fwd-perfect.cc (limited to 'development/c++/fwd-perfect.cc') 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 +#include +#include +#include +#include + +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 +struct option { + static_assert(!std::is_reference_v); + + constexpr option() = default; + + template + 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)...); + } + + ~option() { + reset(); + } + + constexpr T& value() { + assert(m_has_val); + return *reinterpret_cast(m_val); + } + + private: + constexpr void reset() { + if (!m_has_val) { + return; + } + if constexpr (!std::is_trivially_destructible_v) { + 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 opt1(S{}, 123); + + std::puts("==> case 2"); + // invokes M() + M(M&&) + option x /* option(M&&) + M(M&&) */ = M{} /* M() */; +} -- cgit v1.2.3