Index: base/callback.h |
diff --git a/base/callback.h b/base/callback.h |
index e087c731d18e21d2628c8dda75ea69f81f8425b7..059beb4c99f9e852849c7f2d52e5690e06db0f92 100644 |
--- a/base/callback.h |
+++ b/base/callback.h |
@@ -346,21 +346,70 @@ |
namespace base { |
-template <typename R, typename... Args, internal::CopyMode copy_mode> |
-class Callback<R(Args...), copy_mode> |
- : public internal::CallbackBase<copy_mode> { |
+namespace internal { |
+ |
+template <typename CallbackType> |
+class RunMixin; |
+ |
+template <typename R, typename... Args, CopyMode copy_mode> |
+class RunMixin<Callback<R(Args...), copy_mode, RepeatMode::Repeating>> { |
private: |
- using PolymorphicInvoke = R (*)(internal::BindStateBase*, Args&&...); |
+ using CallbackType = Callback<R(Args...), copy_mode, RepeatMode::Repeating>; |
+ using PolymorphicInvoke = R(*)(internal::BindStateBase*, Args&&...); |
public: |
- // 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) 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)...); |
+ } |
+}; |
+ |
+template <typename R, typename... Args> |
+class RunMixin<Callback<R(Args...), CopyMode::MoveOnly, RepeatMode::OneShot>> { |
+ private: |
+ using CallbackType = |
+ Callback<R(Args...), CopyMode::MoveOnly, RepeatMode::OneShot>; |
+ using PolymorphicInvoke = R(*)(internal::BindStateBase*, Args&&...); |
+ |
+ public: |
+ R Run(Args... args) && { |
+ CallbackType cb = std::move(*static_cast<CallbackType*>(this)); |
+ PolymorphicInvoke f = |
+ reinterpret_cast<PolymorphicInvoke>(cb.polymorphic_invoke_); |
+ return f(cb.bind_state_.get(), std::forward<Args>(args)...); |
+ } |
+}; |
+ |
+} // namespace |
+ |
+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>> { |
+ private: |
+ static_assert(repeat_mode != internal::RepeatMode::OneShot || |
+ copy_mode == internal::CopyMode::MoveOnly, |
+ "OneShot Callback must be MoveOnly."); |
+ using PolymorphicInvoke = R(*)(internal::BindStateBase*, Args&&...); |
+ |
+ template <internal::CopyMode other_copy_mode, |
+ internal::RepeatMode other_repeat_mode> |
+ using EnableIfConvertibleFrom = std::enable_if< |
+ (copy_mode != other_copy_mode || repeat_mode != other_repeat_mode) && |
+ (static_cast<int>(copy_mode) <= static_cast<int>(other_copy_mode)) && |
+ (static_cast<int>(repeat_mode) <= static_cast<int>(other_repeat_mode))>; |
+ |
+ public: |
+ using RunType = R(Args...); |
Callback() : internal::CallbackBase<copy_mode>(nullptr) {} |
- Callback(internal::BindStateBase* bind_state, |
- PolymorphicInvoke invoke_func) |
+ Callback(internal::BindStateBase* bind_state, PolymorphicInvoke invoke_func) |
: internal::CallbackBase<copy_mode>(bind_state) { |
using InvokeFuncStorage = |
typename internal::CallbackBase<copy_mode>::InvokeFuncStorage; |
@@ -368,26 +417,30 @@ class Callback<R(Args...), copy_mode> |
reinterpret_cast<InvokeFuncStorage>(invoke_func); |
} |
+ template < |
+ internal::CopyMode other_copy_mode, |
+ internal::RepeatMode other_repeat_mode, |
+ typename = typename EnableIfConvertibleFrom<other_copy_mode, |
+ other_repeat_mode>::type> |
+ Callback(Callback<R(Args...), other_copy_mode, other_repeat_mode> other) |
+ : internal::CallbackBase<copy_mode>(std::move(other)) {} |
+ |
+ template < |
+ internal::CopyMode other_copy_mode, |
+ internal::RepeatMode other_repeat_mode, |
+ typename = typename EnableIfConvertibleFrom<other_copy_mode, |
+ other_repeat_mode>::type> |
+ Callback& operator=( |
+ Callback<R(Args...), other_copy_mode, other_repeat_mode> 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 |