diff --git a/BUILD.bazel b/BUILD.bazel index 9e4656de..d698190e 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -13,6 +13,7 @@ cc_library( srcs = ["indirect.cc"], hdrs = ["indirect.h"], copts = ["-Iexternal/value_types/"], + defines = [], visibility = ["//visibility:public"], deps = ["feature_check"], ) @@ -91,7 +92,9 @@ cc_library( srcs = ["polymorphic.cc"], hdrs = ["polymorphic.h"], copts = ["-Iexternal/value_types/"], + defines = [], visibility = ["//visibility:public"], + deps = ["feature_check"], ) cc_test( @@ -115,6 +118,7 @@ cc_library( copts = ["-Iexternal/value_types/"], defines = ["XYZ_POLYMORPHIC_CXX_14"], visibility = ["//visibility:public"], + deps = ["feature_check"], ) cc_test( 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..f491faeb 100644 --- a/indirect.h +++ b/indirect.h @@ -31,6 +31,20 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. namespace xyz { +#ifndef XYZ_TYPE_IDENTITY_DEFINED +#define XYZ_TYPE_IDENTITY_DEFINED +#ifdef XYZ_HAS_STD_TYPE_IDENTITY +using std::type_identity_t; +#else +template +struct type_identity { + using type = T; +}; +template +using type_identity_t = typename type_identity::type; +#endif // XYZ_HAS_STD_TYPE_IDENTITY +#endif // XYZ_TYPE_IDENTITY_DEFINED + #ifndef XYZ_UNREACHABLE_DEFINED #define XYZ_UNREACHABLE_DEFINED @@ -182,7 +196,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 xyz::type_identity_t& alloc, const indirect& other) : alloc_(alloc) { static_assert(std::copy_constructible); @@ -195,7 +209,7 @@ class indirect { } constexpr indirect( - std::allocator_arg_t, const A& alloc, + std::allocator_arg_t, const xyz::type_identity_t& alloc, indirect&& other) noexcept(allocator_traits::is_always_equal::value) : p_(nullptr), alloc_(alloc) { static_assert(std::move_constructible); @@ -466,8 +480,11 @@ template indirect(Value) -> indirect; template -indirect(std::allocator_arg_t, Alloc, Value) -> indirect< - Value, typename std::allocator_traits::template rebind_alloc>; +indirect(std::allocator_arg_t, Alloc, Value) -> indirect; + +template +indirect(std::allocator_arg_t, Alloc2, indirect) + -> indirect; } // namespace xyz diff --git a/indirect_cxx14.h b/indirect_cxx14.h index c45aeb7c..8883ab76 100644 --- a/indirect_cxx14.h +++ b/indirect_cxx14.h @@ -36,6 +36,20 @@ namespace xyz { struct in_place_t {}; #endif // XYZ_IN_PLACE_DEFINED +#ifndef XYZ_TYPE_IDENTITY_DEFINED +#define XYZ_TYPE_IDENTITY_DEFINED +#ifdef XYZ_HAS_STD_TYPE_IDENTITY +using std::type_identity_t; +#else +template +struct type_identity { + using type = T; +}; +template +using type_identity_t = typename type_identity::type; +#endif // XYZ_HAS_STD_TYPE_IDENTITY +#endif // XYZ_TYPE_IDENTITY_DEFINED + #ifndef XYZ_UNREACHABLE_DEFINED #define XYZ_UNREACHABLE_DEFINED @@ -575,8 +589,11 @@ template indirect(Value) -> indirect; template -indirect(std::allocator_arg_t, Alloc, Value) -> indirect< - Value, typename std::allocator_traits::template rebind_alloc>; +indirect(std::allocator_arg_t, Alloc, Value) -> indirect; + +template +indirect(std::allocator_arg_t, Alloc2, indirect) + -> indirect; #endif // XYZ_HAS_TEMPLATE_ARGUMENT_DEDUCTION } // namespace xyz diff --git a/indirect_test.cc b/indirect_test.cc index f11e6a39..c1014e9c 100644 --- a/indirect_test.cc +++ b/indirect_test.cc @@ -120,13 +120,41 @@ 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); +} + +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_TEMPLATE_ARGUMENT_DEDUCTION diff --git a/polymorphic.h b/polymorphic.h index 57cec8d3..99e9d013 100644 --- a/polymorphic.h +++ b/polymorphic.h @@ -33,6 +33,20 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. namespace xyz { +#ifndef XYZ_TYPE_IDENTITY_DEFINED +#define XYZ_TYPE_IDENTITY_DEFINED +#ifdef XYZ_HAS_STD_TYPE_IDENTITY +using std::type_identity_t; +#else +template +struct type_identity { + using type = T; +}; +template +using type_identity_t = typename type_identity::type; +#endif // XYZ_HAS_STD_TYPE_IDENTITY +#endif // XYZ_TYPE_IDENTITY_DEFINED + #ifndef XYZ_UNREACHABLE_DEFINED #define XYZ_UNREACHABLE_DEFINED @@ -116,6 +130,9 @@ class direct_control_block final : public control_block { } // namespace detail +template +class polymorphic; + template > class polymorphic { using cblock_t = detail::control_block; @@ -241,7 +258,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 xyz::type_identity_t& alloc, const polymorphic& other) : alloc_(alloc) { if (!other.valueless_after_move()) { @@ -252,7 +270,7 @@ class polymorphic { } constexpr polymorphic( - std::allocator_arg_t, const A& alloc, + std::allocator_arg_t, const xyz::type_identity_t& alloc, polymorphic&& other) noexcept(allocator_traits::is_always_equal::value) : alloc_(alloc) { if constexpr (allocator_traits::is_always_equal::value) { @@ -405,6 +423,16 @@ class polymorphic { } }; +template +polymorphic(Value) -> polymorphic; + +template +polymorphic(std::allocator_arg_t, Alloc, Value) -> polymorphic; + +template +polymorphic(std::allocator_arg_t, Alloc2, polymorphic) + -> polymorphic; + } // namespace xyz #endif // XYZ_POLYMORPHIC_H_ diff --git a/polymorphic_cxx14.h b/polymorphic_cxx14.h index 5b611b26..d75c07ca 100644 --- a/polymorphic_cxx14.h +++ b/polymorphic_cxx14.h @@ -27,6 +27,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include #include +#include "feature_check.h" + #ifndef XYZ_POLYMORPHIC_HAS_EXTENDED_CONSTRUCTORS #define XYZ_POLYMORPHIC_HAS_EXTENDED_CONSTRUCTORS 1 #endif // XYZ_POLYMORPHIC_HAS_EXTENDED_CONSTRUCTORS @@ -40,6 +42,22 @@ struct in_place_type_t {}; } // namespace xyz #endif // XYZ_IN_PLACE_TYPE_DEFINED +#ifndef XYZ_TYPE_IDENTITY_DEFINED +#define XYZ_TYPE_IDENTITY_DEFINED +namespace xyz { +#ifdef XYZ_HAS_STD_TYPE_IDENTITY +using std::type_identity_t; +#else +template +struct type_identity { + using type = T; +}; +template +using type_identity_t = typename type_identity::type; +#endif // XYZ_HAS_STD_TYPE_IDENTITY +} // namespace xyz +#endif // XYZ_TYPE_IDENTITY_DEFINED + #ifndef XYZ_UNREACHABLE_DEFINED #define XYZ_UNREACHABLE_DEFINED @@ -319,7 +337,8 @@ class polymorphic : private detail::empty_base_optimization { typename std::remove_reference::type>::type>{}, std::forward(u)) {} - polymorphic(std::allocator_arg_t, const A& alloc, const polymorphic& other) + polymorphic(std::allocator_arg_t, const xyz::type_identity_t& alloc, + const polymorphic& other) : alloc_base(alloc) { if (!other.valueless_after_move()) { cb_ = other.cb_->clone(alloc_base::get()); @@ -335,7 +354,7 @@ class polymorphic : private detail::empty_base_optimization { other) {} polymorphic( - std::allocator_arg_t, const A& alloc, + std::allocator_arg_t, const xyz::type_identity_t& alloc, polymorphic&& other) noexcept(allocator_traits::is_always_equal::value) : alloc_base(alloc) { if (allocator_traits::propagate_on_container_copy_assignment::value) { @@ -476,6 +495,18 @@ class polymorphic : private detail::empty_base_optimization { } }; +#ifdef XYZ_HAS_TEMPLATE_ARGUMENT_DEDUCTION +template +polymorphic(Value) -> polymorphic; + +template +polymorphic(std::allocator_arg_t, Alloc, Value) -> polymorphic; + +template +polymorphic(std::allocator_arg_t, Alloc2, polymorphic) + -> polymorphic; +#endif // XYZ_HAS_TEMPLATE_ARGUMENT_DEDUCTION + } // namespace xyz #endif // XYZ_POLYMORPHIC_H_ diff --git a/polymorphic_test.cc b/polymorphic_test.cc index 152be267..40e5c76c 100644 --- a/polymorphic_test.cc +++ b/polymorphic_test.cc @@ -869,4 +869,48 @@ TEST(PolymorphicTest, TaggedAllocatorsNotEqualMoveConstructFromValueless) { iii.valueless_after_move()); // NOLINT(clang-analyzer-cplusplus.Move) } +#ifdef XYZ_HAS_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_TEMPLATE_ARGUMENT_DEDUCTION + } // namespace