Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2942)

Unified Diff: base/bind_helpers.h

Issue 1496403002: base: Stop using Pass() on move-only types in Bind and Callback. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | base/callback_internal.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: base/bind_helpers.h
diff --git a/base/bind_helpers.h b/base/bind_helpers.h
index 24063ad1ce58fd27c5535ec81c294c597db841df..43aa7ea7ac3be702de19790bdf0e64175d3c0735 100644
--- a/base/bind_helpers.h
+++ b/base/bind_helpers.h
@@ -111,7 +111,7 @@
// scoped_ptr<Foo> f(new Foo());
//
// // |cb| is given ownership of Foo(). |f| is now NULL.
-// // You can use f.Pass() in place of &f, but it's more verbose.
+// // You can use std::move(f) in place of &f, but it's more verbose.
// Closure cb = Bind(&TakesOwnership, Passed(&f));
//
// // Run was never called so |cb| still owns Foo() and deletes
@@ -143,6 +143,9 @@
#ifndef BASE_BIND_HELPERS_H_
#define BASE_BIND_HELPERS_H_
+#include <type_traits>
+#include <utility>
+
#include "base/basictypes.h"
#include "base/callback.h"
#include "base/memory/weak_ptr.h"
@@ -359,22 +362,24 @@ class OwnedWrapper {
// created when we are explicitly trying to do a destructive move.
//
// Two notes:
-// 1) PassedWrapper supports any type that has a "Pass()" function.
-// This is intentional. The whitelisting of which specific types we
-// support is maintained by CallbackParamTraits<>.
+// 1) PassedWrapper supports any type that has a move constructor, however
+// the type will need to be specifically whitelisted in order for it to be
+// bound to a Callback. We guard this explicitly at the call of Passed()
+// to make for clear errors. Things not given to Passed() will be forwarded
+// and stored by value which will not work for general move-only types.
// 2) is_valid_ is distinct from NULL because it is valid to bind a "NULL"
// scoper to a Callback and allow the Callback to execute once.
template <typename T>
class PassedWrapper {
public:
- explicit PassedWrapper(T scoper) : is_valid_(true), scoper_(scoper.Pass()) {}
+ explicit PassedWrapper(T&& scoper)
danakj 2015/12/04 20:46:13 This take a T&&, but the T is a class template typ
+ : is_valid_(true), scoper_(std::move(scoper)) {}
PassedWrapper(const PassedWrapper& other)
- : is_valid_(other.is_valid_), scoper_(other.scoper_.Pass()) {
- }
+ : is_valid_(other.is_valid_), scoper_(std::move(other.scoper_)) {}
T Pass() const {
CHECK(is_valid_);
is_valid_ = false;
- return scoper_.Pass();
+ return std::move(scoper_);
}
private:
@@ -567,16 +572,25 @@ static inline internal::OwnedWrapper<T> Owned(T* o) {
}
// We offer 2 syntaxes for calling Passed(). The first takes a temporary and
-// is best suited for use with the return value of a function. The second
-// takes a pointer to the scoper and is just syntactic sugar to avoid having
-// to write Passed(scoper.Pass()).
-template <typename T>
-static inline internal::PassedWrapper<T> Passed(T scoper) {
- return internal::PassedWrapper<T>(scoper.Pass());
+// is best suited for use with the return value of a function. The second takes
+// a pointer to the scoper and is just syntactic sugar to avoid having to write
+// Passed(std::move(scoper)).
+//
+// Both versions of Passed() prevent T from being an lvalue reference. The first
+// via use of enable_if (to prevent reference collapsing from occuring), and the
+// second takes a T* which makes it illegal for T to be a reference.
+template <typename T,
+ typename std::enable_if<!std::is_lvalue_reference<T>::value &&
+ internal::IsMoveOnlyType<T>::value>::type* =
+ nullptr>
+static inline internal::PassedWrapper<T> Passed(T&& scoper) {
danakj 2015/12/04 20:46:13 This one doesn't prevent any move constructors (I
danakj 2015/12/04 20:50:16 I thought about this some more and I don't think I
dcheng 2015/12/04 20:59:08 I think what you're seeing is copy elision. Is the
danakj 2015/12/04 21:05:25 Oh, nope. It saves a move constructor to use T&& h
+ return internal::PassedWrapper<T>(std::move(scoper));
}
-template <typename T>
+template <typename T,
+ typename std::enable_if<internal::IsMoveOnlyType<T>::value>::type* =
+ nullptr>
static inline internal::PassedWrapper<T> Passed(T* scoper) {
- return internal::PassedWrapper<T>(scoper->Pass());
+ return internal::PassedWrapper<T>(std::move(*scoper));
}
template <typename T>
« no previous file with comments | « no previous file | base/callback_internal.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698