init: fix hiding of move constructors of Result<T>

This is needed to have Result<Result<T>> work correctly.

Test: init unit tests
Change-Id: If7d23d1ea13f3727b567d3baf0eee1d8d0e5a196
This commit is contained in:
Tom Cherry 2017-09-12 14:44:56 -07:00
parent 4ed58aff38
commit d1c9cd0499
2 changed files with 51 additions and 2 deletions

View file

@ -153,8 +153,14 @@ inline Error ErrnoError() {
template <typename T>
class Result {
public:
template <typename... U>
Result(U&&... result) : contents_(std::in_place_index_t<0>(), std::forward<U>(result)...) {}
Result() {}
template <typename U, typename... V,
typename = std::enable_if_t<!(std::is_same_v<std::decay_t<U>, Result<T>> &&
sizeof...(V) == 0)>>
Result(U&& result, V&&... results)
: contents_(std::in_place_index_t<0>(), std::forward<U>(result),
std::forward<V>(results)...) {}
Result(Error&& error) : contents_(std::in_place_index_t<1>(), error.str(), error.get_errno()) {}
Result(const ResultError& result_error)

View file

@ -276,6 +276,49 @@ TEST(result, no_copy_on_return) {
EXPECT_EQ(0U, ConstructorTracker::move_assignment_called);
}
// Below two tests require that we do not hide the move constructor with our forwarding reference
// constructor. This is done with by disabling the forwarding reference constructor if its first
// and only type is Result<T>.
TEST(result, result_result_with_success) {
auto return_result_result_with_success = []() -> Result<Result<Success>> {
return Result<Success>();
};
auto result = return_result_result_with_success();
ASSERT_TRUE(result);
ASSERT_TRUE(*result);
auto inner_result = result.value();
ASSERT_TRUE(inner_result);
}
TEST(result, result_result_with_failure) {
auto return_result_result_with_error = []() -> Result<Result<Success>> {
return Result<Success>(ResultError("failure string", 6));
};
auto result = return_result_result_with_error();
ASSERT_TRUE(result);
ASSERT_FALSE(*result);
EXPECT_EQ("failure string", result->error_string());
EXPECT_EQ(6, result->error_errno());
}
// This test requires that we disable the forwarding reference constructor if Result<T> is the
// *only* type that we are forwarding. In otherwords, if we are forwarding Result<T>, int to
// construct a Result<T>, then we still need the constructor.
TEST(result, result_two_parameter_constructor_same_type) {
struct TestStruct {
TestStruct(int value) : value_(value) {}
TestStruct(Result<TestStruct> result, int value) : value_(result->value_ * value) {}
int value_;
};
auto return_test_struct = []() -> Result<TestStruct> { return {Result<TestStruct>(6), 6}; };
auto result = return_test_struct();
ASSERT_TRUE(result);
EXPECT_EQ(36, result->value_);
}
TEST(result, die_on_access_failed_result) {
Result<std::string> result = Error();
ASSERT_DEATH(*result, "");