summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--base/callback_internal.h58
-rw-r--r--base/move.h11
-rw-r--r--base/template_util.h9
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_