Commit 51647aaa authored by Aaryaman Sagar's avatar Aaryaman Sagar Committed by Facebook Github Bot

Added rvalue and const rvalue overloads to Try

Summary:
Try was missing some important-ish overloads that help it behave well
in rvalue contexts

Reviewed By: yfeldblum

Differential Revision: D5692021

fbshipit-source-id: c34627b56eb52dceaeb1f00ae930ee3bc6e00306
parent 374d408b
...@@ -117,6 +117,12 @@ const T& Try<T>::value() const & { ...@@ -117,6 +117,12 @@ const T& Try<T>::value() const & {
return value_; return value_;
} }
template <class T>
const T&& Try<T>::value() const && {
throwIfFailed();
return std::move(value_);
}
template <class T> template <class T>
void Try<T>::throwIfFailed() const { void Try<T>::throwIfFailed() const {
switch (contains_) { switch (contains_) {
......
...@@ -135,21 +135,28 @@ class Try { ...@@ -135,21 +135,28 @@ class Try {
* *
* @returns mutable reference to the contained value * @returns mutable reference to the contained value
*/ */
T& value()&; T& value() &;
/* /*
* Get a rvalue reference to the contained value. If the Try contains an * Get a rvalue reference to the contained value. If the Try contains an
* exception it will be rethrown. * exception it will be rethrown.
* *
* @returns rvalue reference to the contained value * @returns rvalue reference to the contained value
*/ */
T&& value()&&; T&& value() &&;
/* /*
* Get a const reference to the contained value. If the Try contains an * Get a const reference to the contained value. If the Try contains an
* exception it will be rethrown. * exception it will be rethrown.
* *
* @returns const reference to the contained value * @returns const reference to the contained value
*/ */
const T& value() const&; const T& value() const &;
/*
* Get a const rvalue reference to the contained value. If the Try contains an
* exception it will be rethrown.
*
* @returns const rvalue reference to the contained value
*/
const T&& value() const &&;
/* /*
* If the Try contains an exception, rethrow it. Otherwise do nothing. * If the Try contains an exception, rethrow it. Otherwise do nothing.
...@@ -162,13 +169,35 @@ class Try { ...@@ -162,13 +169,35 @@ class Try {
* *
* @returns const reference to the contained value * @returns const reference to the contained value
*/ */
const T& operator*() const { return value(); } const T& operator*() const & {
return value();
}
/* /*
* Dereference operator. If the Try contains an exception it will be rethrown. * Dereference operator. If the Try contains an exception it will be rethrown.
* *
* @returns mutable reference to the contained value * @returns mutable reference to the contained value
*/ */
T& operator*() { return value(); } T& operator*() & {
return value();
}
/*
* Mutable rvalue dereference operator. If the Try contains an exception it
* will be rethrown.
*
* @returns rvalue reference to the contained value
*/
T&& operator*() && {
return std::move(value());
}
/*
* Const rvalue dereference operator. If the Try contains an exception it
* will be rethrown.
*
* @returns rvalue reference to the contained value
*/
const T&& operator*() const && {
return std::move(value());
}
/* /*
* Const arrow operator. If the Try contains an exception it will be * Const arrow operator. If the Try contains an exception it will be
......
...@@ -36,6 +36,18 @@ class A { ...@@ -36,6 +36,18 @@ class A {
private: private:
int x_; int x_;
}; };
class MoveConstructOnly {
public:
MoveConstructOnly() = default;
MoveConstructOnly(const MoveConstructOnly&) = delete;
MoveConstructOnly(MoveConstructOnly&&) = default;
};
class MutableContainer {
public:
mutable MoveConstructOnly val;
};
} }
TEST(Try, basic) { TEST(Try, basic) {
...@@ -59,6 +71,64 @@ TEST(Try, in_place_nested) { ...@@ -59,6 +71,64 @@ TEST(Try, in_place_nested) {
EXPECT_EQ(5, t_t_a.value().value().x()); EXPECT_EQ(5, t_t_a.value().value().x());
} }
TEST(Try, MoveDereference) {
auto ptr = std::make_unique<int>(1);
auto t = Try<std::unique_ptr<int>>{std::move(ptr)};
auto result = *std::move(t);
EXPECT_EQ(*result, 1);
}
TEST(Try, MoveConstRvalue) {
// tests to see if Try returns a const Rvalue, this is required in the case
// where for example MutableContainer has a mutable memebr that is move only
// and you want to fetch the value from the Try and move it into a member
{
const Try<MutableContainer> t{in_place};
auto val = MoveConstructOnly{std::move(t).value().val};
static_cast<void>(val);
}
{
const Try<MutableContainer> t{in_place};
auto val = (*(std::move(t))).val;
static_cast<void>(val);
}
}
TEST(Try, ValueOverloads) {
using ML = int&;
using MR = int&&;
using CL = const int&;
using CR = const int&&;
{
auto obj = Try<int>{};
using ActualML = decltype(obj.value());
using ActualMR = decltype(std::move(obj).value());
using ActualCL = decltype(as_const(obj).value());
using ActualCR = decltype(std::move(as_const(obj)).value());
EXPECT_TRUE((std::is_same<ML, ActualML>::value));
EXPECT_TRUE((std::is_same<MR, ActualMR>::value));
EXPECT_TRUE((std::is_same<CL, ActualCL>::value));
EXPECT_TRUE((std::is_same<CR, ActualCR>::value));
}
{
auto obj = Try<int>{3};
EXPECT_EQ(obj.value(), 3);
EXPECT_EQ(std::move(obj).value(), 3);
EXPECT_EQ(as_const(obj).value(), 3);
EXPECT_EQ(std::move(as_const(obj)).value(), 3);
}
{
auto obj = Try<int>{make_exception_wrapper<std::range_error>("oops")};
EXPECT_THROW(obj.value(), std::range_error);
EXPECT_THROW(std::move(obj.value()), std::range_error);
EXPECT_THROW(as_const(obj.value()), std::range_error);
EXPECT_THROW(std::move(as_const(obj.value())), std::range_error);
}
}
// Make sure we can copy Trys for copyable types // Make sure we can copy Trys for copyable types
TEST(Try, copy) { TEST(Try, copy) {
Try<int> t; Try<int> t;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment