static constexpr bool nxMoveCtor{
std::is_nothrow_move_constructible<T>::value};
+ // used to disable copy construction and assignment
+ class NonImplementedType;
+
public:
using LockedPtr = typename Base::LockedPtr;
using ConstLockedPtr = typename Base::ConstLockedPtr;
* Note that the copy constructor may throw because it acquires a lock in
* the contextualRLock() method
*/
- Synchronized(const Synchronized& rhs) /* may throw */
+ public:
+ /* implicit */ Synchronized(typename std::conditional<
+ std::is_copy_constructible<T>::value,
+ const Synchronized&,
+ NonImplementedType>::type rhs) /* may throw */
: Synchronized(rhs, rhs.contextualRLock()) {}
/**
* mutex. It locks the two objects in ascending order of their
* addresses.
*/
- Synchronized& operator=(const Synchronized& rhs) {
+ Synchronized& operator=(typename std::conditional<
+ std::is_copy_assignable<T>::value,
+ const Synchronized&,
+ NonImplementedType>::type rhs) {
if (this == &rhs) {
// Self-assignment, pass.
} else if (this < &rhs) {
EXPECT_EQ((CountPair{4, 4}), FakeMutex::getLockUnlockCount());
}
+TEST_F(SynchronizedLockTest, TestCopyConstructibleValues) {
+ struct NonCopyConstructible {
+ NonCopyConstructible(const NonCopyConstructible&) = delete;
+ NonCopyConstructible& operator=(const NonCopyConstructible&) = delete;
+ };
+ struct CopyConstructible {};
+ EXPECT_FALSE(std::is_copy_constructible<
+ folly::Synchronized<NonCopyConstructible>>::value);
+ EXPECT_FALSE(std::is_copy_assignable<
+ folly::Synchronized<NonCopyConstructible>>::value);
+ EXPECT_TRUE(std::is_copy_constructible<
+ folly::Synchronized<CopyConstructible>>::value);
+ EXPECT_TRUE(
+ std::is_copy_assignable<folly::Synchronized<CopyConstructible>>::value);
+}
+
TEST_F(SynchronizedLockTest, UpgradableLocking) {
folly::Synchronized<int, FakeAllPowerfulAssertingMutex> sync;