diff --git a/riegeli/base/initializer.h b/riegeli/base/initializer.h index d502b859..06df4c25 100644 --- a/riegeli/base/initializer.h +++ b/riegeli/base/initializer.h @@ -196,6 +196,34 @@ class InitializerValueBase : public InitializerBase { T && (*reference_)(void* context, ReferenceStorage& reference_storage); }; +// Part of `Initializer` for `T` being a non-reference move-assignable type. +template +class InitializerAssignableValueBase : public InitializerValueBase { + public: + // Makes `object` equivalent to the constructed `T`. This avoids constructing + // a temporary `T` and moving from it. + void AssignTo(T& object) && { assign_to_(this->context(), object); } + + protected: + template < + typename Arg, + std::enable_if_t, + InitializerAssignableValueBase>::value, + int> = 0> + explicit InitializerAssignableValueBase(Arg&& arg); + + template + explicit InitializerAssignableValueBase(std::tuple&& args); + + InitializerAssignableValueBase(InitializerAssignableValueBase&& other) = + default; + InitializerAssignableValueBase& operator=(InitializerAssignableValueBase&&) = + delete; + + private: + void (*assign_to_)(void* context, T& object); +}; + } // namespace initializer_internal // A parameter of type `Initializer` allows the caller to specify a `T` by @@ -214,7 +242,8 @@ class InitializerValueBase : public InitializerBase { // Primary definition of `Initializer` for non-reference move-assignable types. template -class Initializer : public initializer_internal::InitializerValueBase { +class Initializer + : public initializer_internal::InitializerAssignableValueBase { public: // Constructs `Initializer` from a value convertible to `T`. template < @@ -223,7 +252,8 @@ class Initializer : public initializer_internal::InitializerValueBase { std::decay_t, Initializer>>, std::is_convertible>::value, int> = 0> - /*implicit*/ Initializer(Arg&& arg ABSL_ATTRIBUTE_LIFETIME_BOUND); + /*implicit*/ Initializer(Arg&& arg ABSL_ATTRIBUTE_LIFETIME_BOUND) + : Initializer::InitializerAssignableValueBase(std::forward(arg)) {} // Constructs `Initializer` from a tuple of constructor arguments for `T` // (usually made with `std::forward_as_tuple()`). @@ -231,17 +261,11 @@ class Initializer : public initializer_internal::InitializerValueBase { typename... Args, std::enable_if_t::value, int> = 0> /*implicit*/ Initializer( - std::tuple&& args ABSL_ATTRIBUTE_LIFETIME_BOUND); + std::tuple&& args ABSL_ATTRIBUTE_LIFETIME_BOUND) + : Initializer::InitializerAssignableValueBase(std::move(args)) {} Initializer(Initializer&& other) = default; Initializer& operator=(Initializer&&) = delete; - - // Makes `object` equivalent to the constructed `T`. This avoids constructing - // a temporary `T` and moving from it. - void AssignTo(T& object) && { assign_to_(this->context(), object); } - - private: - void (*assign_to_)(void* context, T& object); }; // Specialization of `Initializer` for non-reference non-assignable types. @@ -396,28 +420,27 @@ inline T&& InitializerValueBase::ReferenceMethod( return *std::move(reference_storage); } -} // namespace initializer_internal - -template -template , Initializer>>, - std::is_convertible>::value, - int>> -inline Initializer::Initializer(Arg&& arg) - : Initializer::InitializerValueBase(std::forward(arg)), +template +template < + typename Arg, + std::enable_if_t, + InitializerAssignableValueBase>::value, + int>> +inline InitializerAssignableValueBase::InitializerAssignableValueBase( + Arg&& arg) + : InitializerAssignableValueBase::InitializerValueBase( + std::forward(arg)), assign_to_([](void* context, T& object) { riegeli::Reset( object, std::forward( *static_cast*>(context))); }) {} -template -template ::value, int>> -inline Initializer::Initializer(std::tuple&& args) - : Initializer::InitializerValueBase(std::move(args)), +template +template +inline InitializerAssignableValueBase::InitializerAssignableValueBase( + std::tuple&& args) + : InitializerAssignableValueBase::InitializerValueBase(std::move(args)), assign_to_([](void* context, T& object) { absl::apply( [&](Args&&... args) { @@ -426,6 +449,8 @@ inline Initializer::Initializer(std::tuple&& args) std::move(*static_cast*>(context))); }) {} +} // namespace initializer_internal + } // namespace riegeli #endif // RIEGELI_BASE_INITIALIZER_H_