diff --git a/BUILD.bazel b/BUILD.bazel index 9e4656de..bb5c22ff 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -13,6 +13,7 @@ cc_library( srcs = ["indirect.cc"], hdrs = ["indirect.h"], copts = ["-Iexternal/value_types/"], + defines = ["XYZ_HAS_EXTENDED_CONSTRUCTOR_TEMPLATE_ARGUMENT_DEDUCTION"], visibility = ["//visibility:public"], deps = ["feature_check"], ) @@ -91,6 +92,7 @@ cc_library( srcs = ["polymorphic.cc"], hdrs = ["polymorphic.h"], copts = ["-Iexternal/value_types/"], + defines = ["XYZ_HAS_EXTENDED_CONSTRUCTOR_TEMPLATE_ARGUMENT_DEDUCTION"], visibility = ["//visibility:public"], ) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9ea6f117..0e151aa8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -39,6 +39,7 @@ target_sources(xyz_value_types xyz_add_library( NAME indirect ALIAS xyz_value_types::indirect + DEFINITIONS XYZ_HAS_EXTENDED_CONSTRUCTOR_TEMPLATE_ARGUMENT_DEDUCTION ) target_sources(indirect INTERFACE @@ -75,6 +76,7 @@ target_sources(indirect_cxx17 xyz_add_library( NAME polymorphic ALIAS xyz_value_types::polymorphic + DEFINITIONS XYZ_HAS_EXTENDED_CONSTRUCTOR_TEMPLATE_ARGUMENT_DEDUCTION ) target_sources(polymorphic INTERFACE diff --git a/feature_check.h b/feature_check.h index 429f0adc..504a5ece 100644 --- a/feature_check.h +++ b/feature_check.h @@ -95,4 +95,18 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #endif //(__cplusplus >= 202002L) || (defined(_MSVC_LANG) && _MSVC_LANG >= // 202002L) +// +// XYZ_HAS_STD_TYPE_IDENTITY +// The macro is defined when std::type_identity_t is available. +// + +#ifdef XYZ_HAS_STD_TYPE_IDENTITY +#error "XYZ_HAS_STD_TYPE_IDENTITY is already defined" +#endif // XYZ_HAS_STD_TYPE_IDENTITY + +#if (__cplusplus >= 202002L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L) +#define XYZ_HAS_STD_TYPE_IDENTITY +#endif //(__cplusplus >= 202002L) || (defined(_MSVC_LANG) && _MSVC_LANG >= +// 202002L) + #endif // XYZ_FEATURE_CHECK_H diff --git a/indirect.h b/indirect.h index 7869cc4c..09b5eba2 100644 --- a/indirect.h +++ b/indirect.h @@ -182,7 +182,7 @@ class indirect { p_ = construct_from(alloc_, ilist, std::forward(us)...); } - constexpr indirect(std::allocator_arg_t, const A& alloc, + constexpr indirect(std::allocator_arg_t, const std::type_identity_t& alloc, const indirect& other) : alloc_(alloc) { static_assert(std::copy_constructible); @@ -195,7 +195,7 @@ class indirect { } constexpr indirect( - std::allocator_arg_t, const A& alloc, + std::allocator_arg_t, const std::type_identity_t& alloc, indirect&& other) noexcept(allocator_traits::is_always_equal::value) : p_(nullptr), alloc_(alloc) { static_assert(std::move_constructible); @@ -465,10 +465,17 @@ concept is_hashable = requires(T t) { std::hash{}(t); }; template indirect(Value) -> indirect; -template +template , int> = 0> indirect(std::allocator_arg_t, Alloc, Value) -> indirect< Value, typename std::allocator_traits::template rebind_alloc>; +#ifdef XYZ_HAS_EXTENDED_CONSTRUCTOR_TEMPLATE_ARGUMENT_DEDUCTION +template +indirect(std::allocator_arg_t, std::type_identity_t, + indirect) -> indirect; +#endif // XYZ_HAS_EXTENDED_CONSTRUCTOR_TEMPLATE_ARGUMENT_DEDUCTION + } // namespace xyz template diff --git a/indirect_test.cc b/indirect_test.cc index 9d9b99d3..f80b9570 100644 --- a/indirect_test.cc +++ b/indirect_test.cc @@ -120,14 +120,46 @@ TEST(IndirectTest, AllocatorExtendedInitializerListConstructor) { #ifdef XYZ_HAS_TEMPLATE_ARGUMENT_DEDUCTION TEST(IndirectTest, TemplateArgumentDeduction) { - xyz::indirect a(42); - EXPECT_EQ(*a, 42); + xyz::indirect i(42); + EXPECT_EQ(*i, 42); +} + +TEST(IndirectTest, TemplateArgumentDeductionCopy) { + xyz::indirect i(42); + xyz::indirect ii(i); + + static_assert(std::is_same_v); + EXPECT_EQ(*ii, 42); } TEST(IndirectTest, TemplateArgumentDeductionWithAllocator) { - xyz::indirect a(std::allocator_arg, std::allocator{}, 42); - EXPECT_EQ(*a, 42); + xyz::indirect i(std::allocator_arg, xyz::TaggedAllocator(1), 42); + + static_assert( + std::is_same_v>); + EXPECT_EQ(*i, 42); +} + +#ifdef XYZ_HAS_STD_TYPE_IDENTITY +#ifdef XYZ_HAS_EXTENDED_CONSTRUCTOR_TEMPLATE_ARGUMENT_DEDUCTION +TEST(IndirectTest, TemplateArgumentDeductionWithDeducedAllocatorAndCopy) { + xyz::indirect i(std::allocator_arg, xyz::TaggedAllocator(1), 42); + xyz::indirect ii(std::allocator_arg, 2, i); + + static_assert(std::is_same_v); + EXPECT_EQ(*ii, 42); + EXPECT_EQ(ii.get_allocator().tag, 2); +} + +TEST(IndirectTest, TemplateArgumentDeductionWithDeducedAllocatorAndMove) { + xyz::indirect i(std::allocator_arg, xyz::TaggedAllocator(1), 42); + xyz::indirect ii(std::allocator_arg, 2, std::move(i)); + EXPECT_EQ(*ii, 42); + EXPECT_EQ(ii.get_allocator().tag, 2); } +#endif // XYZ_HAS_EXTENDED_CONSTRUCTOR_TEMPLATE_ARGUMENT_DEDUCTION +#endif // XYZ_HAS_STD_TYPE_IDENTITY #endif // XYZ_HAS_TEMPLATE_ARGUMENT_DEDUCTION template > diff --git a/polymorphic.h b/polymorphic.h index 57cec8d3..b27a6ca6 100644 --- a/polymorphic.h +++ b/polymorphic.h @@ -116,6 +116,15 @@ class direct_control_block final : public control_block { } // namespace detail +template +class polymorphic; + +template +inline constexpr bool is_polymorphic_v = false; + +template +inline constexpr bool is_polymorphic_v> = true; + template > class polymorphic { using cblock_t = detail::control_block; @@ -241,7 +250,8 @@ class polymorphic { cb_ = create_control_block(ilist, std::forward(ts)...); } - constexpr polymorphic(std::allocator_arg_t, const A& alloc, + constexpr polymorphic(std::allocator_arg_t, + const std::type_identity_t& alloc, const polymorphic& other) : alloc_(alloc) { if (!other.valueless_after_move()) { @@ -252,7 +262,7 @@ class polymorphic { } constexpr polymorphic( - std::allocator_arg_t, const A& alloc, + std::allocator_arg_t, const std::type_identity_t& alloc, polymorphic&& other) noexcept(allocator_traits::is_always_equal::value) : alloc_(alloc) { if constexpr (allocator_traits::is_always_equal::value) { @@ -404,7 +414,19 @@ class polymorphic { } } }; - +#ifdef XYZ_HAS_EXTENDED_CONSTRUCTOR_TEMPLATE_ARGUMENT_DEDUCTION +template +polymorphic(Value) -> polymorphic; + +template , int> = 0> +polymorphic(std::allocator_arg_t, Alloc, Value) -> polymorphic< + Value, typename std::allocator_traits::template rebind_alloc>; + +template +polymorphic(std::allocator_arg_t, std::type_identity_t, + polymorphic) -> polymorphic; +#endif // XYZ_HAS_EXTENDED_CONSTRUCTOR_TEMPLATE_ARGUMENT_DEDUCTION } // namespace xyz #endif // XYZ_POLYMORPHIC_H_ diff --git a/polymorphic_test.cc b/polymorphic_test.cc index 4d2c64d9..e0b8c007 100644 --- a/polymorphic_test.cc +++ b/polymorphic_test.cc @@ -845,4 +845,52 @@ TEST(PolymorphicTest, TaggedAllocatorsNotEqualMoveConstructFromValueless) { EXPECT_TRUE(iii.valueless_after_move()); } +#ifdef XYZ_HAS_TEMPLATE_ARGUMENT_DEDUCTION +#ifdef XYZ_HAS_STD_TYPE_IDENTITY +#ifdef XYZ_HAS_EXTENDED_CONSTRUCTOR_TEMPLATE_ARGUMENT_DEDUCTION +TEST(PolymorphicTest, TemplateArgumentDeduction) { + xyz::polymorphic p(Derived(4)); + + EXPECT_EQ(p->value(), 4); +} + +TEST(PolymorphicTest, TemplateArgumentDeductionCopy) { + xyz::polymorphic p(Derived(4)); + xyz::polymorphic pp(p); + + static_assert(std::is_same_v); + + EXPECT_EQ(pp->value(), 4); +} + +TEST(PolymorphicTest, TemplateArgumentDeductionWithAllocator) { + xyz::TaggedAllocator a(1); + xyz::polymorphic p(std::allocator_arg, a, Derived(4)); + + EXPECT_EQ(p->value(), 4); + EXPECT_EQ(p.get_allocator().tag, 1); +} + +TEST(PolymorphicTest, TemplateArgumentDeductionWithDeducedAllocatorAndCopy) { + xyz::TaggedAllocator a(1); + xyz::polymorphic p(std::allocator_arg, a, Derived(4)); + xyz::polymorphic pp(std::allocator_arg, 2, p); + + EXPECT_EQ(pp->value(), 4); + EXPECT_EQ(pp.get_allocator().tag, 2); +} + +TEST(PolymorphicTest, TemplateArgumentDeductionWithDeducedAllocatorAndMove) { + xyz::TaggedAllocator a(1); + xyz::polymorphic p(std::allocator_arg, a, Derived(4)); + xyz::polymorphic pp(std::allocator_arg, 2, std::move(p)); + + EXPECT_EQ(pp->value(), 4); + EXPECT_EQ(pp.get_allocator().tag, 2); +} + +#endif // XYZ_HAS_EXTENDED_CONSTRUCTOR_TEMPLATE_ARGUMENT_DEDUCTION +#endif // XYZ_HAS_STD_TYPE_IDENTITY +#endif // XYZ_HAS_TEMPLATE_ARGUMENT_DEDUCTION + } // namespace