diff options
Diffstat (limited to 'absl/types')
-rw-r--r-- | absl/types/optional.h | 9 | ||||
-rw-r--r-- | absl/types/optional_test.cc | 53 |
2 files changed, 49 insertions, 13 deletions
diff --git a/absl/types/optional.h b/absl/types/optional.h index a86dea92c4ac..c0488797adaa 100644 --- a/absl/types/optional.h +++ b/absl/types/optional.h @@ -513,10 +513,11 @@ class optional : private optional_internal::optional_data<T>, // the arguments `std::forward<Args>(args)...` within the `optional`. // (The `in_place_t` is a tag used to indicate that the contained object // should be constructed in-place.) - // - // TODO(absl-team): Add std::is_constructible<T, Args&&...> SFINAE. - template <typename... Args> - constexpr explicit optional(in_place_t, Args&&... args) + template <typename InPlaceT, typename... Args, + absl::enable_if_t<absl::conjunction< + std::is_same<InPlaceT, in_place_t>, + std::is_constructible<T, Args&&...> >::value>* = nullptr> + constexpr explicit optional(InPlaceT, Args&&... args) : data_base(in_place_t(), absl::forward<Args>(args)...) {} // Constructs a non-empty `optional` direct-initialized value of type `T` from diff --git a/absl/types/optional_test.cc b/absl/types/optional_test.cc index b93aa98e3010..68842abb20e5 100644 --- a/absl/types/optional_test.cc +++ b/absl/types/optional_test.cc @@ -157,6 +157,16 @@ struct NonMovable { NonMovable& operator=(NonMovable&&) = delete; }; +struct NoDefault { + NoDefault() = delete; + NoDefault(const NoDefault&) {} + NoDefault& operator=(const NoDefault&) { return *this; } +}; + +struct ConvertsFromInPlaceT { + ConvertsFromInPlaceT(absl::in_place_t) {} // NOLINT +}; + TEST(optionalTest, DefaultConstructor) { absl::optional<int> empty; EXPECT_FALSE(empty); @@ -337,16 +347,18 @@ TEST(optionalTest, InPlaceConstructor) { static_assert((*opt2).x == ConstexprType::kCtorInitializerList, ""); #endif - // TODO(absl-team): uncomment these when std::is_constructible<T, Args&&...> - // SFINAE is added to optional::optional(absl::in_place_t, Args&&...). - // struct I { - // I(absl::in_place_t); - // }; + EXPECT_FALSE((std::is_constructible<absl::optional<ConvertsFromInPlaceT>, + absl::in_place_t>::value)); + EXPECT_FALSE((std::is_constructible<absl::optional<ConvertsFromInPlaceT>, + const absl::in_place_t&>::value)); + EXPECT_TRUE( + (std::is_constructible<absl::optional<ConvertsFromInPlaceT>, + absl::in_place_t, absl::in_place_t>::value)); - // EXPECT_FALSE((std::is_constructible<absl::optional<I>, - // absl::in_place_t>::value)); - // EXPECT_FALSE((std::is_constructible<absl::optional<I>, const - // absl::in_place_t&>::value)); + EXPECT_FALSE((std::is_constructible<absl::optional<NoDefault>, + absl::in_place_t>::value)); + EXPECT_FALSE((std::is_constructible<absl::optional<NoDefault>, + absl::in_place_t&&>::value)); } // template<U=T> optional(U&&); @@ -1624,4 +1636,27 @@ TEST(optionalTest, AssignmentConstraints) { EXPECT_TRUE(absl::is_copy_assignable<absl::optional<AnyLike>>::value); } +struct NestedClassBug { + struct Inner { + bool dummy = false; + }; + absl::optional<Inner> value; +}; + +TEST(optionalTest, InPlaceTSFINAEBug) { + NestedClassBug b; + ((void)b); + using Inner = NestedClassBug::Inner; + + EXPECT_TRUE((std::is_default_constructible<Inner>::value)); + EXPECT_TRUE((std::is_constructible<Inner>::value)); + EXPECT_TRUE( + (std::is_constructible<absl::optional<Inner>, absl::in_place_t>::value)); + + absl::optional<Inner> o(absl::in_place); + EXPECT_TRUE(o.has_value()); + o.emplace(); + EXPECT_TRUE(o.has_value()); +} + } // namespace |