| // Copyright 2023 The ChromiumOS Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| // Alternative implementation of NoDefault (see no_default_init.h) that provides |
| // slightly different semantics. Like the other type, it disables the default |
| // constructor in order to force to you explicitly initialize the value while |
| // supporting all other constructors of the underlying type. |
| // |
| // However, unlike NoDefault this type does not attempt to be automatically |
| // convertible to the underlying type and instead provides pointer-like |
| // semantics requiring an explicit dereference. This makes it similar to the |
| // API of std::optional, minus the "might not contain a value" part. |
| // |
| // The main advantage of using this implementation is that it can work with any |
| // type, including final types which cannot be subclassed. It also provides a |
| // more consistent API that always works the same way, whereas with NoDefault if |
| // implicit conversion fails you have to do explicit conversion, which is more |
| // awkward than a dereference. The main disadvantage is that you always have to |
| // use a dereference to access the underlying value. |
| |
| #ifndef LIBHWSEC_FOUNDATION_UTILITY_EXPLICIT_INIT_H_ |
| #define LIBHWSEC_FOUNDATION_UTILITY_EXPLICIT_INIT_H_ |
| |
| #include <type_traits> |
| #include <utility> |
| |
| namespace hwsec_foundation { |
| |
| template <typename T> |
| class ExplicitInit final { |
| public: |
| ExplicitInit() = delete; |
| |
| // Define conversion constructors that can construct the underlying type T |
| // from any other type T can be constructed from. We use a conditional |
| // explicit so that U -> ExplicitInit<T> has the same explicit-ness as U -> T. |
| template <typename U> |
| constexpr explicit(!std::is_convertible_v<U, T>) ExplicitInit(U&& u) |
| : value_(std::forward<U>(u)) {} // NOLINT(runtime/explicit) |
| |
| // Define a generic forwarding constructor that works with any multi-argument |
| // T constructors. This uses perfect forwarding like the other single-arg |
| // constructors but it's not important for us to emulate "explicit". |
| template <typename First, typename Second, typename... Rest> |
| constexpr ExplicitInit(First&& first, Second&& second, Rest&&... rest) |
| : value_(std::forward<First>(first), |
| std::forward<Second>(second), |
| std::forward<Rest>(rest)...) {} |
| |
| constexpr ExplicitInit(const ExplicitInit&) = default; |
| constexpr ExplicitInit(ExplicitInit&&) = default; |
| constexpr ExplicitInit& operator=(const ExplicitInit&) = default; |
| constexpr ExplicitInit& operator=(ExplicitInit&&) = default; |
| |
| constexpr const T& operator*() const { return value_; } |
| constexpr T& operator*() { return value_; } |
| |
| constexpr const T* operator->() const { return &value_; } |
| constexpr T* operator->() { return &value_; } |
| |
| constexpr T& value() { return value_; } |
| constexpr const T& value() const { return value_; } |
| |
| private: |
| T value_; |
| }; |
| |
| } // namespace hwsec_foundation |
| |
| #endif // LIBHWSEC_FOUNDATION_UTILITY_EXPLICIT_INIT_H_ |