blob: ea1ef2ce3eda511e3257f0a46a1dc6ca43bb6f79 [file] [log] [blame] [edit]
// 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_