diff options
-rw-r--r-- | base/callback_internal.h | 58 | ||||
-rw-r--r-- | base/move.h | 11 | ||||
-rw-r--r-- | base/template_util.h | 9 |
3 files changed, 46 insertions, 32 deletions
diff --git a/base/callback_internal.h b/base/callback_internal.h index 5993824..e66623c 100644 --- a/base/callback_internal.h +++ b/base/callback_internal.h @@ -67,6 +67,20 @@ class BASE_EXPORT CallbackBase { InvokeFuncStorage polymorphic_invoke_; }; +// A helper template to determine if given type is non-const move-only-type, +// i.e. if a value of the given type should be passed via .Pass() in a +// destructive way. +template <typename T> struct IsMoveOnlyType { + template <typename U> + static YesType Test(const typename U::MoveOnlyTypeForCPP03*); + + template <typename U> + static NoType Test(...); + + static const bool value = sizeof(Test<T>(0)) == sizeof(YesType) && + !is_const<T>::value; +}; + // This is a typetraits object that's used to take an argument type, and // extract a suitable type for storing and forwarding arguments. // @@ -78,7 +92,7 @@ class BASE_EXPORT CallbackBase { // parameters by const reference. In this case, we end up passing an actual // array type in the initializer list which C++ does not allow. This will // break passing of C-string literals. -template <typename T> +template <typename T, bool is_move_only = IsMoveOnlyType<T>::value> struct CallbackParamTraits { typedef const T& ForwardType; typedef T StorageType; @@ -90,7 +104,7 @@ struct CallbackParamTraits { // // The ForwardType should only be used for unbound arguments. template <typename T> -struct CallbackParamTraits<T&> { +struct CallbackParamTraits<T&, false> { typedef T& ForwardType; typedef T StorageType; }; @@ -101,14 +115,14 @@ struct CallbackParamTraits<T&> { // T[n]" does not seem to match correctly, so we are stuck with this // restriction. template <typename T, size_t n> -struct CallbackParamTraits<T[n]> { +struct CallbackParamTraits<T[n], false> { typedef const T* ForwardType; typedef const T* StorageType; }; // See comment for CallbackParamTraits<T[n]>. template <typename T> -struct CallbackParamTraits<T[]> { +struct CallbackParamTraits<T[], false> { typedef const T* ForwardType; typedef const T* StorageType; }; @@ -126,26 +140,10 @@ struct CallbackParamTraits<T[]> { // correctness, because we are implementing a destructive move. A non-const // reference cannot be used with temporaries which means the result of a // function or a cast would not be usable with Callback<> or Bind(). -// -// TODO(ajwong): We might be able to use SFINAE to search for the existence of -// a Pass() function in the type and avoid the whitelist in CallbackParamTraits -// and CallbackForward. -template <typename T, typename D> -struct CallbackParamTraits<scoped_ptr<T, D> > { - typedef scoped_ptr<T, D> ForwardType; - typedef scoped_ptr<T, D> StorageType; -}; - -template <typename T, typename R> -struct CallbackParamTraits<scoped_ptr_malloc<T, R> > { - typedef scoped_ptr_malloc<T, R> ForwardType; - typedef scoped_ptr_malloc<T, R> StorageType; -}; - template <typename T> -struct CallbackParamTraits<ScopedVector<T> > { - typedef ScopedVector<T> ForwardType; - typedef ScopedVector<T> StorageType; +struct CallbackParamTraits<T, true> { + typedef T ForwardType; + typedef T StorageType; }; // CallbackForward() is a very limited simulation of C++11's std::forward() @@ -165,18 +163,14 @@ struct CallbackParamTraits<ScopedVector<T> > { // parameter to another callback. This is to support Callbacks that return // the movable-but-not-copyable types whitelisted above. template <typename T> -T& CallbackForward(T& t) { return t; } - -template <typename T, typename D> -scoped_ptr<T, D> CallbackForward(scoped_ptr<T, D>& p) { return p.Pass(); } - -template <typename T, typename R> -scoped_ptr_malloc<T, R> CallbackForward(scoped_ptr_malloc<T, R>& p) { - return p.Pass(); +typename enable_if<!IsMoveOnlyType<T>::value, T>::type& CallbackForward(T& t) { + return t; } template <typename T> -ScopedVector<T> CallbackForward(ScopedVector<T>& p) { return p.Pass(); } +typename enable_if<IsMoveOnlyType<T>::value, T>::type CallbackForward(T& t) { + return t.Pass(); +} } // namespace internal } // namespace base diff --git a/base/move.h b/base/move.h index d2cd3df..1c67155 100644 --- a/base/move.h +++ b/base/move.h @@ -136,6 +136,16 @@ // choose the one that adheres to the standard. // // +// WHY HAVE typedef void MoveOnlyTypeForCPP03 +// +// Callback<>/Bind() needs to understand movable-but-not-copyable semantics +// to call .Pass() appropriately when it is expected to transfer the value. +// The cryptic typedef MoveOnlyTypeForCPP03 is added to make this check +// easy and automatic in helper templates for Callback<>/Bind(). +// See IsMoveOnlyType template and its usage in base/callback_internal.h +// for more details. +// +// // COMPARED TO C++11 // // In C++11, you would implement this functionality using an r-value reference @@ -202,6 +212,7 @@ public: \ operator rvalue_type() { return rvalue_type(this); } \ type Pass() { return type(rvalue_type(this)); } \ + typedef void MoveOnlyTypeForCPP03; \ private: #endif // BASE_MOVE_H_ diff --git a/base/template_util.h b/base/template_util.h index e21d4dc..30572f1 100644 --- a/base/template_util.h +++ b/base/template_util.h @@ -39,6 +39,9 @@ template <class T> struct is_non_const_reference : false_type {}; template <class T> struct is_non_const_reference<T&> : true_type {}; template <class T> struct is_non_const_reference<const T&> : false_type {}; +template <class T> struct is_const : false_type {}; +template <class T> struct is_const<const T> : true_type {}; + template <class T> struct is_void : false_type {}; template <> struct is_void<void> : true_type {}; @@ -103,6 +106,12 @@ struct is_class sizeof(internal::YesType)> { }; +template<bool B, class T = void> +struct enable_if {}; + +template<class T> +struct enable_if<true, T> { typedef T type; }; + } // namespace base #endif // BASE_TEMPLATE_UTIL_H_ |