diff options
author | Johannes Stoelp <johannes.stoelp@gmail.com> | 2024-04-05 00:26:31 +0200 |
---|---|---|
committer | Johannes Stoelp <johannes.stoelp@gmail.com> | 2024-04-05 00:26:31 +0200 |
commit | 35690469481a9bbdf8cc3d1e882fc5f82392e909 (patch) | |
tree | 8533e0c6b524b9dfd9cb2ea2b5b4a663cce33485 | |
download | cpp-templates-35690469481a9bbdf8cc3d1e882fc5f82392e909.tar.gz cpp-templates-35690469481a9bbdf8cc3d1e882fc5f82392e909.zip |
dtor: conditional trivial destructible
-rw-r--r-- | cond_trivial_destr.cc | 94 |
1 files changed, 94 insertions, 0 deletions
diff --git a/cond_trivial_destr.cc b/cond_trivial_destr.cc new file mode 100644 index 0000000..8186e6b --- /dev/null +++ b/cond_trivial_destr.cc @@ -0,0 +1,94 @@ +#if 0 +set -xe +g++ -std=c++20 -fsyntax-only cond_trivial_destr.cc +clang++ -std=c++20 -fsyntax-only cond_trivial_destr.cc +exit 0 +#endif + +#include <type_traits> + +// Conditional trivial destructible. +// +// Since destructors can't have template parameters, std::enable_if can't be +// used to selectively enable or disable the destructor via SFINAE. +// +// If a template class wants to be trivially destructible depending on the +// template parameter, one has to work around it with some template +// specialization (pre cpp20). The implementation in the namespace v1 gives an +// example for that. +// +// Starting with cpp20 we can leverage concepts to enable / disable different +// destructor implementations. The implementations in the namespace v2 gives an +// example for that. + +// -- PRE CPP20 ---------------------------------------------------------------- + +namespace v1 { +template <typename T, bool = std::is_trivially_destructible_v<T>> +struct storage { + ~storage() { + if (has_val) { + val.~T(); + has_val = false; + } + } + + union { + T val; + }; + bool has_val = false; +}; + +template <typename T> +struct storage<T, true> { + union { + T val; + }; +}; + +template <typename T> +struct option : private storage<T> {}; +} // namespace v1 + +// -- SINCE CPP20 -------------------------------------------------------------- + +namespace v2 { +#if __cplusplus >= 202002L +template <typename T> +struct option { + ~option() = default; + ~option() + requires(!std::is_trivially_destructible_v<T>) + { + val.~T(); + } + +private: + union { + T val; + }; + bool has_value = false; +}; +#endif +} // namespace v2 + +// -- TESTEE ------------------------------------------------------------------- + +struct trivial {}; +static_assert(std::is_trivially_destructible_v<trivial>, ""); + +struct non_trivial { + ~non_trivial() { + } +}; +static_assert(!std::is_trivially_destructible_v<non_trivial>, ""); + +// -- TEST --------------------------------------------------------------------- + +static_assert(std::is_trivially_destructible_v<v1::option<trivial>>, ""); +static_assert(!std::is_trivially_destructible_v<v1::option<non_trivial>>, ""); + +#if __cplusplus >= 202002L +static_assert(std::is_trivially_destructible_v<v2::option<trivial>>, ""); +static_assert(!std::is_trivially_destructible_v<v2::option<non_trivial>>, ""); +#endif |