diff --git a/googlemock/include/gmock/gmock-actions.h b/googlemock/include/gmock/gmock-actions.h index f95be3f03..fb33f7bfa 100644 --- a/googlemock/include/gmock/gmock-actions.h +++ b/googlemock/include/gmock/gmock-actions.h @@ -1480,68 +1480,72 @@ namespace internal { // TYPE DIRECTLY. struct ExcessiveArg {}; -// A helper class needed for implementing the ACTION* macros. -template -class ActionHelper { - public: - template - static Result Perform(Impl* impl, const std::tuple& args) { - static constexpr size_t kMaxArgs = sizeof...(Ts) <= 10 ? sizeof...(Ts) : 10; - return Apply(impl, args, MakeIndexSequence{}, - MakeIndexSequence<10 - kMaxArgs>{}); +// Builds an implementation of an Action<> for some particular signature, using +// a class defined by an ACTION* macro. +template struct ActionImpl; + +template +struct ImplBase { + struct Holder { + // Allows each copy of the Action<> to get to the Impl. + explicit operator const Impl&() const { return *ptr; } + std::shared_ptr ptr; + }; + using type = typename std::conditional::value, + Impl, Holder>::type; +}; + +template +struct ActionImpl : ImplBase::type { + using Base = typename ImplBase::type; + using function_type = R(Args...); + using args_type = std::tuple; + + ActionImpl() = default; // Only defined if appropriate for Base. + explicit ActionImpl(std::shared_ptr impl) : Base{std::move(impl)} { } + + R operator()(Args&&... arg) const { + static constexpr size_t kMaxArgs = + sizeof...(Args) <= 10 ? sizeof...(Args) : 10; + return Apply(MakeIndexSequence{}, + MakeIndexSequence<10 - kMaxArgs>{}, + args_type{std::forward(arg)...}); } - private: - template - static Result Apply(Impl* impl, const std::tuple& args, - IndexSequence, IndexSequence) { - return impl->template gmock_PerformImpl< - typename std::tuple_element>::type...>( - args, std::get(args)..., - ((void)rest_ids, ExcessiveArg())...); + template + R Apply(IndexSequence, IndexSequence, + const args_type& args) const { + // Impl need not be specific to the signature of action being implemented; + // only the implementing function body needs to have all of the specific + // types instantiated. Up to 10 of the args that are provided by the + // args_type get passed, followed by a dummy of unspecified type for the + // remainder up to 10 explicit args. + static const ExcessiveArg kExcessArg; + return static_cast(*this).template gmock_PerformImpl< + /*function_type=*/function_type, /*return_type=*/R, + /*args_type=*/args_type, + /*argN_type=*/typename std::tuple_element::type...>( + /*args=*/args, std::get(args)..., + ((void)excess_id, kExcessArg)...); } }; -// A helper base class needed for implementing the ACTION* macros. -// Implements constructor and conversion operator for Action. -// -// Template specialization for parameterless Action. -template -class ActionImpl { - public: - ActionImpl() = default; +// Stores a default-constructed Impl as part of the Action<>'s +// std::function<>. The Impl should be trivial to copy. +template +::testing::Action MakeAction() { + return ::testing::Action(ActionImpl()); +} - template - operator ::testing::Action() const { // NOLINT(runtime/explicit) - return ::testing::Action(new typename Derived::template gmock_Impl()); - } -}; - -// Template specialization for parameterized Action. -template