#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 // 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 > struct storage { ~storage() { if (has_val) { val.~T(); has_val = false; } } union { T val; }; bool has_val = false; }; template struct storage { union { T val; }; }; template struct option : private storage {}; } // namespace v1 // -- SINCE CPP20 -------------------------------------------------------------- namespace v2 { #if __cplusplus >= 202002L template struct option { ~option() = default; ~option() requires(!std::is_trivially_destructible_v) { val.~T(); } private: union { T val; }; bool has_value = false; }; #endif } // namespace v2 // -- TESTEE ------------------------------------------------------------------- struct trivial {}; static_assert(std::is_trivially_destructible_v, ""); struct non_trivial { ~non_trivial() { } }; static_assert(!std::is_trivially_destructible_v, ""); // -- TEST --------------------------------------------------------------------- static_assert(std::is_trivially_destructible_v>, ""); static_assert(!std::is_trivially_destructible_v>, ""); #if __cplusplus >= 202002L static_assert(std::is_trivially_destructible_v>, ""); static_assert(!std::is_trivially_destructible_v>, ""); #endif