mirror of
https://github.com/google/googletest.git
synced 2024-12-26 17:41:03 +08:00
gmock-actions: support ByMove in a specialization of ReturnAction.
Rather than branching on whether the return type is ByMoveWrapper within ReturnAction itself, hoist the distinction to outside. This allows the main class template to be modified without worrying about this special case, which means we can stop using a shared pointer to the value (introduced as a linked_ptr in commit 3d1c78b2bf to support ByMove) in this commit and simplify the class template further in a future commit with the eventual aim of directly supporting move-only result types. PiperOrigin-RevId: 445938943 Change-Id: I7bc71ea301d5e493ac6ecbe57d62738a48a2721a
This commit is contained in:
parent
8ded48c37b
commit
5176726123
@ -900,12 +900,12 @@ struct ByMoveWrapper {
|
||||
// of gtl::Container() is passed into Return.
|
||||
//
|
||||
template <typename R>
|
||||
class ReturnAction {
|
||||
class ReturnAction final {
|
||||
public:
|
||||
// Constructs a ReturnAction object from the value to be returned.
|
||||
// 'value' is passed by value instead of by const reference in order
|
||||
// to allow Return("string literal") to compile.
|
||||
explicit ReturnAction(R value) : value_(new R(std::move(value))) {}
|
||||
explicit ReturnAction(R value) : value_(std::move(value)) {}
|
||||
|
||||
// This template type conversion operator allows Return(x) to be
|
||||
// used in ANY function that returns x's type.
|
||||
@ -924,19 +924,19 @@ class ReturnAction {
|
||||
"use ReturnRef instead of Return to return a reference");
|
||||
static_assert(!std::is_void<Result>::value,
|
||||
"Can't use Return() on an action expected to return `void`.");
|
||||
return Action<F>(new Impl<R, F>(value_));
|
||||
return Action<F>(new Impl<F>(value_));
|
||||
}
|
||||
|
||||
private:
|
||||
// Implements the Return(x) action for a particular function type F.
|
||||
template <typename R_, typename F>
|
||||
template <typename F>
|
||||
class Impl : public ActionInterface<F> {
|
||||
public:
|
||||
typedef typename Function<F>::Result Result;
|
||||
typedef typename Function<F>::ArgumentTuple ArgumentTuple;
|
||||
|
||||
explicit Impl(const std::shared_ptr<R>& value)
|
||||
: value_before_cast_(*value),
|
||||
explicit Impl(const R& value)
|
||||
: value_before_cast_(value),
|
||||
// Make an implicit conversion to Result before initializing the
|
||||
// Result object we store, avoiding calling any explicit constructor
|
||||
// of Result from R.
|
||||
@ -961,30 +961,39 @@ class ReturnAction {
|
||||
Impl& operator=(const Impl&) = delete;
|
||||
};
|
||||
|
||||
// Partially specialize for ByMoveWrapper. This version of ReturnAction will
|
||||
// move its contents instead.
|
||||
template <typename R_, typename F>
|
||||
class Impl<ByMoveWrapper<R_>, F> : public ActionInterface<F> {
|
||||
public:
|
||||
typedef typename Function<F>::Result Result;
|
||||
typedef typename Function<F>::ArgumentTuple ArgumentTuple;
|
||||
R value_;
|
||||
};
|
||||
|
||||
explicit Impl(const std::shared_ptr<R>& wrapper)
|
||||
: performed_(false), wrapper_(wrapper) {}
|
||||
// A specialization of ReturnAction<R> when R is ByMoveWrapper<T> for some T.
|
||||
//
|
||||
// This version applies the type system-defeating hack of moving from T even in
|
||||
// the const call operator, checking at runtime that it isn't called more than
|
||||
// once, since the user has declared their intent to do so by using ByMove.
|
||||
template <typename T>
|
||||
class ReturnAction<ByMoveWrapper<T>> final {
|
||||
public:
|
||||
explicit ReturnAction(ByMoveWrapper<T> wrapper)
|
||||
: state_(new State(std::move(wrapper.payload))) {}
|
||||
|
||||
Result Perform(const ArgumentTuple&) override {
|
||||
GTEST_CHECK_(!performed_)
|
||||
<< "A ByMove() action should only be performed once.";
|
||||
performed_ = true;
|
||||
return std::move(wrapper_->payload);
|
||||
}
|
||||
T operator()() const {
|
||||
GTEST_CHECK_(!state_->called)
|
||||
<< "A ByMove() action must be performed at most once.";
|
||||
|
||||
private:
|
||||
bool performed_;
|
||||
const std::shared_ptr<R> wrapper_;
|
||||
state_->called = true;
|
||||
return std::move(state_->value);
|
||||
}
|
||||
|
||||
private:
|
||||
// We store our state on the heap so that we are copyable as required by
|
||||
// Action, despite the fact that we are stateful and T may not be copyable.
|
||||
struct State {
|
||||
explicit State(T&& value_in) : value(std::move(value_in)) {}
|
||||
|
||||
T value;
|
||||
bool called = false;
|
||||
};
|
||||
|
||||
const std::shared_ptr<R> value_;
|
||||
const std::shared_ptr<State> state_;
|
||||
};
|
||||
|
||||
// Implements the ReturnNull() action.
|
||||
|
Loading…
x
Reference in New Issue
Block a user