Skip to content

Add a second cpp2::range constructor which takes 2 types, and deduce the common type for them (if available) #1270

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

Merged
merged 5 commits into from
Oct 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions include/cpp2util.h
Original file line number Diff line number Diff line change
Expand Up @@ -746,6 +746,11 @@ concept valid_custom_is_operator = predicate_member_fun<X, F, &F::op_is>
|| brace_initializable_to<X, argument_of_op_is_t<F>>
);

template <typename T, typename U>
concept has_common_type = requires (T t, U u) {
typename std::common_type_t<T, U>;
};

//-----------------------------------------------------------------------
//
// General helpers
Expand Down Expand Up @@ -2437,6 +2442,19 @@ class range
}
}

// When the first & last types are different, use a CTAD deduction guide
// to find the `std::common_type` for them, if one exists. See below
// after the class definition for the deduction guide.
template <typename U>
requires has_common_type<T, U>
range(
T const& f,
U const& l,
bool include_last = false
)
: range(f, l, include_last)
{}

class iterator
{
TT first = T{};
Expand Down Expand Up @@ -2572,6 +2590,16 @@ class range
}
};

// CTAD deduction guide for the `range` constructor that takes two different types.
// Deduces the `std::common_type` for them, if one exists.
template <typename T, typename U>
requires has_common_type<T, U>
range(
T const& f,
U const& l,
bool include_last = false
) -> range<std::common_type_t<T, U>>;

template<typename T>
constexpr auto contains(range<T> const& r, T const& t)
-> bool
Expand Down
5 changes: 5 additions & 0 deletions regression-tests/pure2-range-operators.cpp2
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ main: () = {
std::cout << " (e)$ (v[e])$\n";
}

std::cout << "\nAnd test the range when mixing signed & unsigned types:\n";
for 0 ..< v.size() do (e) {
std::cout << " (e)$ (v[e])$\n";
}

all_about: std::list =
( "Hokey", "Pokey" );

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
pure2-last-use.cpp2:273:36: error: expected variable name or 'this' in lambda capture list
public: std::add_pointer_t<int([[maybe_unused]] cpp2::impl::in<int> unnamed_param_1)> g;
^
pure2-last-use.cpp2:329:2: error: expected '>'
};
^
pure2-last-use.cpp2:273:30: note: to match this '<'
public: std::add_pointer_t<int([[maybe_unused]] cpp2::impl::in<int> unnamed_param_1)> g;
^
pure2-last-use.cpp2:344:16: error: no template named 'move_only_function' in namespace 'std'
public: std::move_only_function<int()> b;
~~~~~^
pure2-last-use.cpp2:348:161: error: no member named 'move_only_function' in namespace 'std'
CPP2_REQUIRES_ (std::is_convertible_v<CPP2_TYPEOF(a_), std::add_const_t<std::unique_ptr<int>>&> && std::is_convertible_v<CPP2_TYPEOF(b_), std::add_const_t<std::move_only_function<int()>>&> && std::is_convertible_v<CPP2_TYPEOF(c_), std::add_const_t<std::add_lvalue_reference_t<int>>&>) ;
~~~~~^
../../../include/cpp2util.h:10008:43: note: expanded from macro 'CPP2_REQUIRES_'
#define CPP2_REQUIRES_(...) requires (__VA_ARGS__)
^~~~~~~~~~~
pure2-last-use.cpp2:348:188: error: expected expression
CPP2_REQUIRES_ (std::is_convertible_v<CPP2_TYPEOF(a_), std::add_const_t<std::unique_ptr<int>>&> && std::is_convertible_v<CPP2_TYPEOF(b_), std::add_const_t<std::move_only_function<int()>>&> && std::is_convertible_v<CPP2_TYPEOF(c_), std::add_const_t<std::add_lvalue_reference_t<int>>&>) ;
^
pure2-last-use.cpp2:348:193: error: use of address-of-label extension outside of a function body
CPP2_REQUIRES_ (std::is_convertible_v<CPP2_TYPEOF(a_), std::add_const_t<std::unique_ptr<int>>&> && std::is_convertible_v<CPP2_TYPEOF(b_), std::add_const_t<std::move_only_function<int()>>&> && std::is_convertible_v<CPP2_TYPEOF(c_), std::add_const_t<std::add_lvalue_reference_t<int>>&>) ;
^
pure2-last-use.cpp2:773:69: error: no template named 'move_only_function' in namespace 'std'
auto issue_888_1([[maybe_unused]] std::string unnamed_param_1, std::move_only_function<int([[maybe_unused]] cpp2::impl::in<int> unnamed_param_1)> size) -> void;
~~~~~^
pure2-last-use.cpp2:773:93: error: expected variable name or 'this' in lambda capture list
auto issue_888_1([[maybe_unused]] std::string unnamed_param_1, std::move_only_function<int([[maybe_unused]] cpp2::impl::in<int> unnamed_param_1)> size) -> void;
^
pure2-last-use.cpp2:773:156: error: expected unqualified-id
auto issue_888_1([[maybe_unused]] std::string unnamed_param_1, std::move_only_function<int([[maybe_unused]] cpp2::impl::in<int> unnamed_param_1)> size) -> void;
^
pure2-last-use.cpp2:773:160: error: expected '>'
auto issue_888_1([[maybe_unused]] std::string unnamed_param_1, std::move_only_function<int([[maybe_unused]] cpp2::impl::in<int> unnamed_param_1)> size) -> void;
^
pure2-last-use.cpp2:773:87: note: to match this '<'
auto issue_888_1([[maybe_unused]] std::string unnamed_param_1, std::move_only_function<int([[maybe_unused]] cpp2::impl::in<int> unnamed_param_1)> size) -> void;
^
pure2-last-use.cpp2:773:160: error: expected ')'
auto issue_888_1([[maybe_unused]] std::string unnamed_param_1, std::move_only_function<int([[maybe_unused]] cpp2::impl::in<int> unnamed_param_1)> size) -> void;
^
pure2-last-use.cpp2:773:17: note: to match this '('
auto issue_888_1([[maybe_unused]] std::string unnamed_param_1, std::move_only_function<int([[maybe_unused]] cpp2::impl::in<int> unnamed_param_1)> size) -> void;
^
pure2-last-use.cpp2:271:7: error: missing '}' at end of definition of 'issue_857_4'
class issue_857_4 {
^
pure2-last-use.cpp2:905:1: note: still within definition of 'issue_857_4' here
namespace captures {
^
pure2-last-use.cpp2:279:272: error: no member named 'move_only_function' in namespace 'std'
requires (std::is_convertible_v<CPP2_TYPEOF(f_), std::add_const_t<std::add_pointer_t<int()>>&> && std::is_convertible_v<CPP2_TYPEOF(g_), std::add_const_t<std::add_pointer_t<int(cpp2::impl::in<int> in_)>>&> && std::is_convertible_v<CPP2_TYPEOF(mf_), std::add_const_t<std::move_only_function<int()>>&> && std::is_convertible_v<CPP2_TYPEOF(mg_), std::add_const_t<std::move_only_function<int(cpp2::impl::in<int> in_)>>&>)
~~~~~^
pure2-last-use.cpp2:279:299: error: expected expression
requires (std::is_convertible_v<CPP2_TYPEOF(f_), std::add_const_t<std::add_pointer_t<int()>>&> && std::is_convertible_v<CPP2_TYPEOF(g_), std::add_const_t<std::add_pointer_t<int(cpp2::impl::in<int> in_)>>&> && std::is_convertible_v<CPP2_TYPEOF(mf_), std::add_const_t<std::move_only_function<int()>>&> && std::is_convertible_v<CPP2_TYPEOF(mg_), std::add_const_t<std::move_only_function<int(cpp2::impl::in<int> in_)>>&>)
^
pure2-last-use.cpp2:279:304: error: use of address-of-label extension outside of a function body
requires (std::is_convertible_v<CPP2_TYPEOF(f_), std::add_const_t<std::add_pointer_t<int()>>&> && std::is_convertible_v<CPP2_TYPEOF(g_), std::add_const_t<std::add_pointer_t<int(cpp2::impl::in<int> in_)>>&> && std::is_convertible_v<CPP2_TYPEOF(mf_), std::add_const_t<std::move_only_function<int()>>&> && std::is_convertible_v<CPP2_TYPEOF(mg_), std::add_const_t<std::move_only_function<int(cpp2::impl::in<int> in_)>>&>)
^
pure2-last-use.cpp2:278:14: error: out-of-line definition of 'issue_857_4' does not match any declaration in 'issue_857_4'
issue_857_4::issue_857_4(auto&& f_, auto&& g_, auto&& mf_, auto&& mg_)
^~~~~~~~~~~
pure2-last-use.cpp2:281:272: error: member initializer 'g' does not name a non-static data member or base class
, g{ CPP2_FORWARD(g_) }
^~~~~~~~~~~~~~~~~~~~~
pure2-last-use.cpp2:282:272: error: member initializer 'mf' does not name a non-static data member or base class
, mf{ CPP2_FORWARD(mf_) }
^~~~~~~~~~~~~~~~~~~~~~~
pure2-last-use.cpp2:283:272: error: member initializer 'mg' does not name a non-static data member or base class
, mg{ CPP2_FORWARD(mg_) }{}
^~~~~~~~~~~~~~~~~~~~~~~
fatal error: too many errors emitted, stopping now [-ferror-limit=]
20 errors generated.
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,16 @@ And from indexes 1..=5 they are:
4 Elephant
5 Flicker

And test the range when mixing signed & unsigned types:
0 Aardvark
1 Baboon
2 Cat
3 Dolphin
4 Elephant
5 Flicker
6 Grue
7 Wumpus

Make sure non-random-access iterators work:
Hokey
Pokey
Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1 @@
../../../include/cpp2util.h(1103) decltype(auto) cpp2::impl::assert_in_bounds(auto &&, std::source_location) [arg = 5, x:auto = std::vector<int>]: Bounds safety violation: out of bounds access attempt detected - attempted access at index 5, [min,max] range is [0,4]
../../../include/cpp2util.h(1108) decltype(auto) cpp2::impl::assert_in_bounds(auto &&, std::source_location) [arg = 5, x:auto = std::vector<int>]: Bounds safety violation: out of bounds access attempt detected - attempted access at index 5, [min,max] range is [0,4]
Original file line number Diff line number Diff line change
@@ -1 +1 @@
../../../include/cpp2util.h(915) : Bounds safety violation
../../../include/cpp2util.h(920) : Bounds safety violation
Original file line number Diff line number Diff line change
@@ -1 +1 @@
../../../include/cpp2util.h(915) : Contract violation: fill: value must contain at least count elements
../../../include/cpp2util.h(920) : Contract violation: fill: value must contain at least count elements
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
sending error to my framework... [dynamic null dereference attempt detected]
from source location: ../../../include/cpp2util.h(994) decltype(auto) cpp2::impl::assert_not_null(auto &&, std::source_location) [arg:auto = int *&]
from source location: ../../../include/cpp2util.h(999) decltype(auto) cpp2::impl::assert_not_null(auto &&, std::source_location) [arg:auto = int *&]
Original file line number Diff line number Diff line change
@@ -1 +1 @@
../../../include/cpp2util.h(994) decltype(auto) cpp2::impl::assert_not_null(auto &&, std::source_location) [arg:auto = std::expected<int, bool>]: Null safety violation: std::expected has an unexpected value
../../../include/cpp2util.h(999) decltype(auto) cpp2::impl::assert_not_null(auto &&, std::source_location) [arg:auto = std::expected<int, bool>]: Null safety violation: std::expected has an unexpected value
Original file line number Diff line number Diff line change
@@ -1 +1 @@
../../../include/cpp2util.h(994) decltype(auto) cpp2::impl::assert_not_null(auto &&, std::source_location) [arg:auto = std::optional<int>]: Null safety violation: std::optional does not contain a value
../../../include/cpp2util.h(999) decltype(auto) cpp2::impl::assert_not_null(auto &&, std::source_location) [arg:auto = std::optional<int>]: Null safety violation: std::optional does not contain a value
Original file line number Diff line number Diff line change
@@ -1 +1 @@
../../../include/cpp2util.h(994) decltype(auto) cpp2::impl::assert_not_null(auto &&, std::source_location) [arg:auto = std::shared_ptr<int>]: Null safety violation: std::shared_ptr is empty
../../../include/cpp2util.h(999) decltype(auto) cpp2::impl::assert_not_null(auto &&, std::source_location) [arg:auto = std::shared_ptr<int>]: Null safety violation: std::shared_ptr is empty
Original file line number Diff line number Diff line change
@@ -1 +1 @@
../../../include/cpp2util.h(994) decltype(auto) cpp2::impl::assert_not_null(auto &&, std::source_location) [arg:auto = std::unique_ptr<int>]: Null safety violation: std::unique_ptr is empty
../../../include/cpp2util.h(999) decltype(auto) cpp2::impl::assert_not_null(auto &&, std::source_location) [arg:auto = std::unique_ptr<int>]: Null safety violation: std::unique_ptr is empty
Loading
Loading