Index: base/callback.h |
diff --git a/base/callback.h b/base/callback.h |
index d173a3c7b6b47b564e698d02fe60a7b3d1947ca2..ff8d6f9aad30322eb084fc2ad639ae9ab08437fa 100644 |
--- a/base/callback.h |
+++ b/base/callback.h |
@@ -19,15 +19,76 @@ |
namespace base { |
-template <typename R, typename... Args, internal::CopyMode copy_mode> |
-class Callback<R(Args...), copy_mode> |
- : public internal::CallbackBase<copy_mode> { |
+namespace internal { |
+ |
+// RunMixin provides different variant of `Run()` function to `Callback<>` based |
dcheng
2016/09/08 04:09:01
Nit: "different variants" or "a different variant"
tzik
2016/09/12 11:00:34
Done.
|
+// on the type of callback. |
+template <typename CallbackType> |
+class RunMixin; |
+ |
+// Specialization for RepeatingCallback. |
+template <typename R, typename... Args, CopyMode copy_mode> |
+class RunMixin<Callback<R(Args...), copy_mode, RepeatMode::Repeating>> { |
+ private: |
+ using CallbackType = Callback<R(Args...), copy_mode, RepeatMode::Repeating>; |
+ |
+ public: |
+ using PolymorphicInvoke = R(*)(internal::BindStateBase*, Args&&...); |
+ |
+ R Run(Args... args) const { |
+ const CallbackType& cb = static_cast<const CallbackType&>(*this); |
+ PolymorphicInvoke f = |
+ reinterpret_cast<PolymorphicInvoke>(cb.polymorphic_invoke()); |
+ return f(cb.bind_state_.get(), std::forward<Args>(args)...); |
+ } |
+}; |
+ |
+// Specialization for OnceCallback. |
+template <typename R, typename... Args> |
+class RunMixin<Callback<R(Args...), CopyMode::MoveOnly, RepeatMode::Once>> { |
+ private: |
+ using CallbackType = |
+ Callback<R(Args...), CopyMode::MoveOnly, RepeatMode::Once>; |
+ |
public: |
- using PolymorphicInvoke = R (*)(internal::BindStateBase*, Args&&...); |
+ using PolymorphicInvoke = R(*)(internal::BindStateBase*, Args&&...); |
- // MSVC 2013 doesn't support Type Alias of function types. |
- // Revisit this after we update it to newer version. |
- typedef R RunType(Args...); |
+ R Run(Args... args) && { |
+ // Move the callback instance into a local variable before the invocation, |
+ // that ensures the internal state is cleared after the invocation. |
+ // It's not safe to touch |this| after the invocation, since running the |
+ // bound function may destroy |this|. |
+ CallbackType cb = static_cast<CallbackType&&>(*this); |
+ PolymorphicInvoke f = |
+ reinterpret_cast<PolymorphicInvoke>(cb.polymorphic_invoke()); |
+ return f(cb.bind_state_.get(), std::forward<Args>(args)...); |
+ } |
+}; |
+ |
+template <typename From, typename To> |
+struct IsCallbackConvertible : std::false_type {}; |
+ |
+template <typename Signature> |
+struct IsCallbackConvertible< |
+ Callback<Signature, CopyMode::Copyable, RepeatMode::Repeating>, |
+ Callback<Signature, CopyMode::MoveOnly, RepeatMode::Once>> : std::true_type { |
+}; |
+ |
+} // namespace internal |
+ |
+template <typename R, |
+ typename... Args, |
+ internal::CopyMode copy_mode, |
+ internal::RepeatMode repeat_mode> |
+class Callback<R(Args...), copy_mode, repeat_mode> |
+ : public internal::CallbackBase<copy_mode>, |
+ public internal::RunMixin<Callback<R(Args...), copy_mode, repeat_mode>> { |
+ public: |
+ static_assert(repeat_mode != internal::RepeatMode::Once || |
+ copy_mode == internal::CopyMode::MoveOnly, |
+ "OnceCallback must be MoveOnly."); |
+ |
+ using RunType = R(Args...); |
Callback() : internal::CallbackBase<copy_mode>(nullptr) {} |
@@ -35,26 +96,27 @@ class Callback<R(Args...), copy_mode> |
: internal::CallbackBase<copy_mode>(bind_state) { |
} |
+ template <typename OtherCallback, |
+ typename = typename std::enable_if< |
+ internal::IsCallbackConvertible<OtherCallback, Callback>::value |
+ >::type> |
+ Callback(OtherCallback other) |
+ : internal::CallbackBase<copy_mode>(std::move(other)) {} |
+ |
+ template <typename OtherCallback, |
+ typename = typename std::enable_if< |
+ internal::IsCallbackConvertible<OtherCallback, Callback>::value |
+ >::type> |
+ Callback& operator=(OtherCallback other) { |
+ static_cast<internal::CallbackBase<copy_mode>&>(*this) = std::move(other); |
+ return *this; |
+ } |
+ |
bool Equals(const Callback& other) const { |
return this->EqualsInternal(other); |
} |
- // Run() makes an extra copy compared to directly calling the bound function |
- // if an argument is passed-by-value and is copyable-but-not-movable: |
- // i.e. below copies CopyableNonMovableType twice. |
- // void F(CopyableNonMovableType) {} |
- // Bind(&F).Run(CopyableNonMovableType()); |
- // |
- // We can not fully apply Perfect Forwarding idiom to the callchain from |
- // Callback::Run() to the target function. Perfect Forwarding requires |
- // knowing how the caller will pass the arguments. However, the signature of |
- // InvokerType::Run() needs to be fixed in the callback constructor, so Run() |
- // cannot template its arguments based on how it's called. |
- R Run(Args... args) const { |
- PolymorphicInvoke f = |
- reinterpret_cast<PolymorphicInvoke>(this->polymorphic_invoke()); |
- return f(this->bind_state_.get(), std::forward<Args>(args)...); |
- } |
+ friend class internal::RunMixin<Callback>; |
}; |
} // namespace base |