Commit 6eb37d26 authored by Aaryaman Sagar's avatar Aaryaman Sagar Committed by Facebook Github Bot

Initializer list constructor and emplace make_optional versions

Summary: Add a missing initializer list constructor and variadic argument emplacing make_optional variants.

Reviewed By: yfeldblum, ot

Differential Revision: D8918866

fbshipit-source-id: a343602f91b5e0ee0b5c293ca929a699b6104996
parent cd1ab8b9
......@@ -130,9 +130,19 @@ class Optional {
template <typename... Args>
FOLLY_CPP14_CONSTEXPR explicit Optional(in_place_t, Args&&... args) noexcept(
std::is_nothrow_constructible<Value, Args...>::value) {
construct(std::forward<Args>(args)...);
}
std::is_nothrow_constructible<Value, Args...>::value)
: Optional{PrivateConstructor{}, std::forward<Args>(args)...} {}
template <typename U, typename... Args>
FOLLY_CPP14_CONSTEXPR explicit Optional(
in_place_t,
std::initializer_list<U> il,
Args&&... args) noexcept(std::
is_nothrow_constructible<
Value,
std::initializer_list<U>,
Args...>::value)
: Optional{PrivateConstructor{}, il, std::forward<Args>(args)...} {}
// Used only when an Optional is used with coroutines on MSVC
/* implicit */ Optional(const detail::OptionalPromiseReturn<Value>& p)
......@@ -315,6 +325,30 @@ class Optional {
}
private:
template <class T>
friend constexpr Optional<_t<std::decay<T>>> make_optional(T&&);
template <class T, class... Args>
friend constexpr Optional<T> make_optional(Args&&... args);
template <class T, class U, class... As>
friend constexpr Optional<T> make_optional(std::initializer_list<U>, As&&...);
/**
* Construct the optional in place, this is duplicated as a non-explicit
* constructor to allow returning values that are non-movable from
* make_optional using list initialization.
*
* Until C++17, at which point this will become unnecessary because of
* specified prvalue elision.
*/
struct PrivateConstructor {
explicit PrivateConstructor() = default;
};
template <typename... Args>
FOLLY_CPP14_CONSTEXPR Optional(PrivateConstructor, Args&&... args) noexcept(
std::is_constructible<Value, Args&&...>::value) {
construct(std::forward<Args>(args)...);
}
void require_value() const {
if (!storage_.hasValue) {
throw_exception<OptionalEmptyException>();
......@@ -392,9 +426,25 @@ void swap(Optional<T>& a, Optional<T>& b) noexcept(noexcept(a.swap(b))) {
a.swap(b);
}
template <class T, class Opt = Optional<typename std::decay<T>::type>>
constexpr Opt make_optional(T&& v) {
return Opt(std::forward<T>(v));
template <class T>
constexpr Optional<_t<std::decay<T>>> make_optional(T&& v) {
using PrivateConstructor =
typename folly::Optional<_t<std::decay<T>>>::PrivateConstructor;
return {PrivateConstructor{}, std::forward<T>(v)};
}
template <class T, class... Args>
constexpr folly::Optional<T> make_optional(Args&&... args) {
using PrivateConstructor = typename folly::Optional<T>::PrivateConstructor;
return {PrivateConstructor{}, std::forward<Args>(args)...};
}
template <class T, class U, class... Args>
constexpr folly::Optional<T> make_optional(
std::initializer_list<U> il,
Args&&... args) {
using PrivateConstructor = typename folly::Optional<T>::PrivateConstructor;
return {PrivateConstructor{}, il, std::forward<Args>(args)...};
}
///////////////////////////////////////////////////////////////////////////////
......
......@@ -20,9 +20,11 @@
#include <folly/portability/GTest.h>
#include <algorithm>
#include <initializer_list>
#include <iomanip>
#include <memory>
#include <string>
#include <tuple>
#include <type_traits>
#include <unordered_map>
#include <vector>
......@@ -571,6 +573,36 @@ TEST(Optional, Pointee) {
EXPECT_FALSE(get_pointer(x));
}
namespace {
class ConstructibleWithArgsOnly {
public:
explicit ConstructibleWithArgsOnly(int, double) {}
ConstructibleWithArgsOnly() = delete;
ConstructibleWithArgsOnly(const ConstructibleWithArgsOnly&) = delete;
ConstructibleWithArgsOnly(ConstructibleWithArgsOnly&&) = delete;
ConstructibleWithArgsOnly& operator=(const ConstructibleWithArgsOnly&) =
delete;
ConstructibleWithArgsOnly& operator=(ConstructibleWithArgsOnly&&) = delete;
};
class ConstructibleWithInitializerListAndArgsOnly {
public:
ConstructibleWithInitializerListAndArgsOnly(std::initializer_list<int>, int) {
}
ConstructibleWithInitializerListAndArgsOnly() = delete;
ConstructibleWithInitializerListAndArgsOnly(
const ConstructibleWithInitializerListAndArgsOnly&) = delete;
ConstructibleWithInitializerListAndArgsOnly(
ConstructibleWithInitializerListAndArgsOnly&&) = delete;
ConstructibleWithInitializerListAndArgsOnly& operator=(
const ConstructibleWithInitializerListAndArgsOnly&) = delete;
ConstructibleWithInitializerListAndArgsOnly& operator=(
ConstructibleWithInitializerListAndArgsOnly&&) = delete;
};
} // namespace
TEST(Optional, MakeOptional) {
// const L-value version
const std::string s("abc");
......@@ -604,6 +636,34 @@ TEST(Optional, MakeOptional) {
EXPECT_TRUE(pInt.get() == nullptr);
ASSERT_TRUE(optIntPtr.hasValue());
EXPECT_EQ(**optIntPtr, 3);
// variadic version
{
auto&& optional = make_optional<ConstructibleWithArgsOnly>(int{}, double{});
std::ignore = optional;
}
{
using Type = ConstructibleWithInitializerListAndArgsOnly;
auto&& optional = make_optional<Type>({int{}}, double{});
std::ignore = optional;
}
}
TEST(Optional, InitializerListConstruct) {
using Type = ConstructibleWithInitializerListAndArgsOnly;
auto&& optional = Optional<Type>{in_place, {int{}}, double{}};
std::ignore = optional;
}
TEST(Optional, TestDisambiguationMakeOptionalVariants) {
{
auto optional = make_optional<int>(1);
std::ignore = optional;
}
{
auto optional = make_optional(1);
std::ignore = optional;
}
}
TEST(Optional, SelfAssignment) {
......
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