MoveOnly utility
authorGiuseppe Ottaviano <ott@fb.com>
Fri, 23 Jun 2017 22:19:01 +0000 (15:19 -0700)
committerFacebook Github Bot <facebook-github-bot@users.noreply.github.com>
Fri, 23 Jun 2017 22:21:06 +0000 (15:21 -0700)
Summary: Same as `boost::noncopyable` but it does not disable move constructor/assignment.

Reviewed By: luciang

Differential Revision: D5311043

fbshipit-source-id: 44fe95712169b95a00e474385be43fa857cfd8ec

folly/Utility.h
folly/test/UtilityTest.cpp

index 4d6725d7070ec70e9684d19db915100c6fc5e9cc..1d3786181458768f1f8efcb04030b0a6ac963dc8 100644 (file)
@@ -158,4 +158,27 @@ struct Identity {
     return static_cast<T&&>(x);
   }
 };
-}
+
+namespace moveonly_ { // Protection from unintended ADL.
+
+/**
+ * Disallow copy but not move in derived types. This is essentially
+ * boost::noncopyable (the implementation is almost identical) but it
+ * doesn't delete move constructor and move assignment.
+ */
+class MoveOnly {
+ protected:
+  constexpr MoveOnly() = default;
+  ~MoveOnly() = default;
+
+  MoveOnly(MoveOnly&&) = default;
+  MoveOnly& operator=(MoveOnly&&) = default;
+  MoveOnly(const MoveOnly&) = delete;
+  MoveOnly& operator=(const MoveOnly&) = delete;
+};
+
+} // namespace moveonly_
+
+using MoveOnly = moveonly_::MoveOnly;
+
+} // namespace folly
index 9b77e170099aacf96ec1b887f33eec0731f6d4ba..5507b96f8855c193f08667b3a89b0c62bb2491cb 100644 (file)
@@ -14,8 +14,9 @@
  * limitations under the License.
  */
 
-#include <folly/Utility.h>
+#include <type_traits>
 
+#include <folly/Utility.h>
 #include <folly/portability/GTest.h>
 
 namespace {
@@ -88,3 +89,24 @@ TEST(FollyIntegerSequence, core) {
   static_assert(seq3.size() == 3, "");
   EXPECT_EQ(3, seq3.size());
 }
+
+TEST_F(UtilityTest, MoveOnly) {
+  class FooBar : folly::MoveOnly {
+    int a;
+  };
+
+  static_assert(
+      !std::is_copy_constructible<FooBar>::value,
+      "Should not be copy constructible");
+
+  // Test that move actually works.
+  FooBar foobar;
+  FooBar foobar2(std::move(foobar));
+  (void)foobar2;
+
+  // Test that inheriting from MoveOnly doesn't prevent the move
+  // constructor from being noexcept.
+  static_assert(
+      std::is_nothrow_move_constructible<FooBar>::value,
+      "Should have noexcept move constructor");
+}