Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DRAFT] One idea for the deduction guides #558

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
4 changes: 4 additions & 0 deletions BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ cc_library(
srcs = ["indirect.cc"],
hdrs = ["indirect.h"],
copts = ["-Iexternal/value_types/"],
defines = [],
visibility = ["//visibility:public"],
deps = ["feature_check"],
)
Expand Down Expand Up @@ -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(
Expand All @@ -115,6 +118,7 @@ cc_library(
copts = ["-Iexternal/value_types/"],
defines = ["XYZ_POLYMORPHIC_CXX_14"],
visibility = ["//visibility:public"],
deps = ["feature_check"],
)

cc_test(
Expand Down
14 changes: 14 additions & 0 deletions feature_check.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<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
25 changes: 21 additions & 4 deletions indirect.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 <class T>
struct type_identity {
using type = T;
};
template <class T>
using type_identity_t = typename type_identity<T>::type;
#endif // XYZ_HAS_STD_TYPE_IDENTITY
#endif // XYZ_TYPE_IDENTITY_DEFINED

#ifndef XYZ_UNREACHABLE_DEFINED
#define XYZ_UNREACHABLE_DEFINED

Expand Down Expand Up @@ -182,7 +196,7 @@ class indirect {
p_ = construct_from(alloc_, ilist, std::forward<Us>(us)...);
}

constexpr indirect(std::allocator_arg_t, const A& alloc,
constexpr indirect(std::allocator_arg_t, const xyz::type_identity_t<A>& alloc,
const indirect& other)
: alloc_(alloc) {
static_assert(std::copy_constructible<T>);
Expand All @@ -195,7 +209,7 @@ class indirect {
}

constexpr indirect(
std::allocator_arg_t, const A& alloc,
std::allocator_arg_t, const xyz::type_identity_t<A>& alloc,
indirect&& other) noexcept(allocator_traits::is_always_equal::value)
: p_(nullptr), alloc_(alloc) {
static_assert(std::move_constructible<T>);
Expand Down Expand Up @@ -466,8 +480,11 @@ template <typename Value>
indirect(Value) -> indirect<Value>;

template <typename Alloc, typename Value>
indirect(std::allocator_arg_t, Alloc, Value) -> indirect<
Value, typename std::allocator_traits<Alloc>::template rebind_alloc<Value>>;
indirect(std::allocator_arg_t, Alloc, Value) -> indirect<Value, Alloc>;

template <typename Alloc, typename Alloc2, typename Value>
indirect(std::allocator_arg_t, Alloc2, indirect<Value, Alloc>)
-> indirect<Value, Alloc>;

} // namespace xyz

Expand Down
21 changes: 19 additions & 2 deletions indirect_cxx14.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 <class T>
struct type_identity {
using type = T;
};
template <class T>
using type_identity_t = typename type_identity<T>::type;
#endif // XYZ_HAS_STD_TYPE_IDENTITY
#endif // XYZ_TYPE_IDENTITY_DEFINED

#ifndef XYZ_UNREACHABLE_DEFINED
#define XYZ_UNREACHABLE_DEFINED

Expand Down Expand Up @@ -575,8 +589,11 @@ template <typename Value>
indirect(Value) -> indirect<Value>;

template <typename Alloc, typename Value>
indirect(std::allocator_arg_t, Alloc, Value) -> indirect<
Value, typename std::allocator_traits<Alloc>::template rebind_alloc<Value>>;
indirect(std::allocator_arg_t, Alloc, Value) -> indirect<Value, Alloc>;

template <typename Alloc, typename Alloc2, typename Value>
indirect(std::allocator_arg_t, Alloc2, indirect<Value, Alloc>)
-> indirect<Value, Alloc>;
#endif // XYZ_HAS_TEMPLATE_ARGUMENT_DEDUCTION

} // namespace xyz
Expand Down
36 changes: 32 additions & 4 deletions indirect_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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<decltype(i), decltype(ii)>);
EXPECT_EQ(*ii, 42);
}

TEST(IndirectTest, TemplateArgumentDeductionWithAllocator) {
xyz::indirect a(std::allocator_arg, std::allocator<int>{}, 42);
EXPECT_EQ(*a, 42);
xyz::indirect i(std::allocator_arg, xyz::TaggedAllocator<int>(1), 42);

static_assert(
std::is_same_v<decltype(i.get_allocator()), xyz::TaggedAllocator<int>>);
EXPECT_EQ(*i, 42);
}

TEST(IndirectTest, TemplateArgumentDeductionWithDeducedAllocatorAndCopy) {
xyz::indirect i(std::allocator_arg, xyz::TaggedAllocator<int>(1), 42);
xyz::indirect ii(std::allocator_arg, 2, i);

static_assert(std::is_same_v<decltype(i.get_allocator()),
decltype(ii.get_allocator())>);
EXPECT_EQ(*ii, 42);
EXPECT_EQ(ii.get_allocator().tag, 2);
}

TEST(IndirectTest, TemplateArgumentDeductionWithDeducedAllocatorAndMove) {
xyz::indirect i(std::allocator_arg, xyz::TaggedAllocator<int>(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

Expand Down
32 changes: 30 additions & 2 deletions polymorphic.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 <class T>
struct type_identity {
using type = T;
};
template <class T>
using type_identity_t = typename type_identity<T>::type;
#endif // XYZ_HAS_STD_TYPE_IDENTITY
#endif // XYZ_TYPE_IDENTITY_DEFINED

#ifndef XYZ_UNREACHABLE_DEFINED
#define XYZ_UNREACHABLE_DEFINED

Expand Down Expand Up @@ -116,6 +130,9 @@ class direct_control_block final : public control_block<T, A> {

} // namespace detail

template <class T, class A>
class polymorphic;

template <class T, class A = std::allocator<T>>
class polymorphic {
using cblock_t = detail::control_block<T, A>;
Expand Down Expand Up @@ -241,7 +258,8 @@ class polymorphic {
cb_ = create_control_block<U>(ilist, std::forward<Ts>(ts)...);
}

constexpr polymorphic(std::allocator_arg_t, const A& alloc,
constexpr polymorphic(std::allocator_arg_t,
const xyz::type_identity_t<A>& alloc,
const polymorphic& other)
: alloc_(alloc) {
if (!other.valueless_after_move()) {
Expand All @@ -252,7 +270,7 @@ class polymorphic {
}

constexpr polymorphic(
std::allocator_arg_t, const A& alloc,
std::allocator_arg_t, const xyz::type_identity_t<A>& alloc,
polymorphic&& other) noexcept(allocator_traits::is_always_equal::value)
: alloc_(alloc) {
if constexpr (allocator_traits::is_always_equal::value) {
Expand Down Expand Up @@ -405,6 +423,16 @@ class polymorphic {
}
};

template <typename Value>
polymorphic(Value) -> polymorphic<Value>;

template <typename Alloc, typename Value>
polymorphic(std::allocator_arg_t, Alloc, Value) -> polymorphic<Value, Alloc>;

template <typename Alloc, typename Alloc2, typename Value>
polymorphic(std::allocator_arg_t, Alloc2, polymorphic<Value, Alloc>)
-> polymorphic<Value, Alloc>;

} // namespace xyz

#endif // XYZ_POLYMORPHIC_H_
35 changes: 33 additions & 2 deletions polymorphic_cxx14.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#include <type_traits>
#include <utility>

#include "feature_check.h"

#ifndef XYZ_POLYMORPHIC_HAS_EXTENDED_CONSTRUCTORS
#define XYZ_POLYMORPHIC_HAS_EXTENDED_CONSTRUCTORS 1
#endif // XYZ_POLYMORPHIC_HAS_EXTENDED_CONSTRUCTORS
Expand All @@ -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 <class T>
struct type_identity {
using type = T;
};
template <class T>
using type_identity_t = typename type_identity<T>::type;
#endif // XYZ_HAS_STD_TYPE_IDENTITY
} // namespace xyz
#endif // XYZ_TYPE_IDENTITY_DEFINED

#ifndef XYZ_UNREACHABLE_DEFINED
#define XYZ_UNREACHABLE_DEFINED

Expand Down Expand Up @@ -319,7 +337,8 @@ class polymorphic : private detail::empty_base_optimization<A> {
typename std::remove_reference<U>::type>::type>{},
std::forward<U>(u)) {}

polymorphic(std::allocator_arg_t, const A& alloc, const polymorphic& other)
polymorphic(std::allocator_arg_t, const xyz::type_identity_t<A>& alloc,
const polymorphic& other)
: alloc_base(alloc) {
if (!other.valueless_after_move()) {
cb_ = other.cb_->clone(alloc_base::get());
Expand All @@ -335,7 +354,7 @@ class polymorphic : private detail::empty_base_optimization<A> {
other) {}

polymorphic(
std::allocator_arg_t, const A& alloc,
std::allocator_arg_t, const xyz::type_identity_t<A>& alloc,
polymorphic&& other) noexcept(allocator_traits::is_always_equal::value)
: alloc_base(alloc) {
if (allocator_traits::propagate_on_container_copy_assignment::value) {
Expand Down Expand Up @@ -476,6 +495,18 @@ class polymorphic : private detail::empty_base_optimization<A> {
}
};

#ifdef XYZ_HAS_TEMPLATE_ARGUMENT_DEDUCTION
template <typename Value>
polymorphic(Value) -> polymorphic<Value>;

template <typename Alloc, typename Value>
polymorphic(std::allocator_arg_t, Alloc, Value) -> polymorphic<Value, Alloc>;

template <typename Alloc, typename Alloc2, typename Value>
polymorphic(std::allocator_arg_t, Alloc2, polymorphic<Value, Alloc>)
-> polymorphic<Value, Alloc>;
#endif // XYZ_HAS_TEMPLATE_ARGUMENT_DEDUCTION

} // namespace xyz

#endif // XYZ_POLYMORPHIC_H_
44 changes: 44 additions & 0 deletions polymorphic_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -845,4 +845,48 @@ TEST(PolymorphicTest, TaggedAllocatorsNotEqualMoveConstructFromValueless) {
EXPECT_TRUE(iii.valueless_after_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<decltype(p), decltype(pp)>);

EXPECT_EQ(pp->value(), 4);
}

TEST(PolymorphicTest, TemplateArgumentDeductionWithAllocator) {
xyz::TaggedAllocator<Derived> 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<Derived> 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<Derived> 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
Loading