1 //===----------------------------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8
9 // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
10 // There is a bug in older versions of Clang that causes trouble with constraints in classes like
11 // `ContainerWithDirectCtr`.
12 // XFAIL: apple-clang-15
13
14 // template<template<class...> class C, input_range R, class... Args>
15 // constexpr auto to(R&& r, Args&&... args); // Since C++23
16
17 #include <ranges>
18
19 #include <algorithm>
20 #include <array>
21 #include <cassert>
22 #include "container.h"
23
24 template <class ElementType>
25 struct ContainerWithDirectCtr : Container<ElementType, CtrChoice::DirectCtr> {
26 using Container<ElementType, CtrChoice::DirectCtr>::Container;
27 };
28
29 template <std::ranges::input_range Range>
30 ContainerWithDirectCtr(Range&&) -> ContainerWithDirectCtr<std::ranges::range_value_t<Range>>;
31
32 template <std::ranges::input_range Range>
33 ContainerWithDirectCtr(Range&&, int, char) -> ContainerWithDirectCtr<std::ranges::range_value_t<Range>>;
34
35 template <class ElementType>
36 struct ContainerWithFromRangeT : Container<ElementType, CtrChoice::FromRangeT> {
37 using Container<ElementType, CtrChoice::FromRangeT>::Container;
38 };
39
40 template <std::ranges::input_range Range>
41 ContainerWithFromRangeT(std::from_range_t, Range&&) -> ContainerWithFromRangeT<std::ranges::range_value_t<Range>>;
42
43 template <std::ranges::input_range Range>
44 ContainerWithFromRangeT(std::from_range_t, Range&&, int, char) ->
45 ContainerWithFromRangeT<std::ranges::range_value_t<Range>>;
46
47 template <class ElementType>
48 struct ContainerWithBeginEndPair : Container<ElementType, CtrChoice::BeginEndPair> {
49 using Container<ElementType, CtrChoice::BeginEndPair>::Container;
50 };
51
52 template <class Iter>
53 ContainerWithBeginEndPair(Iter, Iter) -> ContainerWithBeginEndPair<std::iter_value_t<Iter>>;
54
55 template <class Iter>
56 ContainerWithBeginEndPair(Iter, Iter, int, char) -> ContainerWithBeginEndPair<std::iter_value_t<Iter>>;
57
test()58 constexpr bool test() {
59 std::array in = {1, 2, 3, 4, 5};
60 int arg1 = 42;
61 char arg2 = 'a';
62
63 { // Case 1 -- can construct directly from the given range.
64 {
65 std::same_as<ContainerWithDirectCtr<int>> decltype(auto) result = std::ranges::to<ContainerWithDirectCtr>(in);
66
67 assert(result.ctr_choice == CtrChoice::DirectCtr);
68 assert(std::ranges::equal(result, in));
69 assert((in | std::ranges::to<ContainerWithDirectCtr>()) == result);
70 }
71
72 { // Extra arguments.
73 std::same_as<ContainerWithDirectCtr<int>> decltype(auto) result =
74 std::ranges::to<ContainerWithDirectCtr>(in, arg1, arg2);
75
76 assert(result.ctr_choice == CtrChoice::DirectCtr);
77 assert(std::ranges::equal(result, in));
78 assert(result.extra_arg1 == arg1);
79 assert(result.extra_arg2 == arg2);
80 assert((in | std::ranges::to<ContainerWithDirectCtr>(arg1, arg2)) == result);
81 }
82 }
83
84 { // Case 2 -- can construct from the given range using the `from_range_t` tagged constructor.
85 {
86 std::same_as<ContainerWithFromRangeT<int>> decltype(auto) result = std::ranges::to<ContainerWithFromRangeT>(in);
87
88 assert(result.ctr_choice == CtrChoice::FromRangeT);
89 assert(std::ranges::equal(result, in));
90 assert((in | std::ranges::to<ContainerWithFromRangeT>()) == result);
91 }
92
93 { // Extra arguments.
94 std::same_as<ContainerWithFromRangeT<int>> decltype(auto) result =
95 std::ranges::to<ContainerWithFromRangeT>(in, arg1, arg2);
96
97 assert(result.ctr_choice == CtrChoice::FromRangeT);
98 assert(std::ranges::equal(result, in));
99 assert(result.extra_arg1 == arg1);
100 assert(result.extra_arg2 == arg2);
101 assert((in | std::ranges::to<ContainerWithFromRangeT>(arg1, arg2)) == result);
102 }
103 }
104
105 { // Case 3 -- can construct from a begin-end iterator pair.
106 {
107 std::same_as<ContainerWithBeginEndPair<int>> decltype(auto) result =
108 std::ranges::to<ContainerWithBeginEndPair>(in);
109
110 assert(result.ctr_choice == CtrChoice::BeginEndPair);
111 assert(std::ranges::equal(result, in));
112 assert((in | std::ranges::to<ContainerWithBeginEndPair>()) == result);
113 }
114
115 { // Extra arguments.
116 std::same_as<ContainerWithBeginEndPair<int>> decltype(auto) result =
117 std::ranges::to<ContainerWithBeginEndPair>(in, arg1, arg2);
118
119 assert(result.ctr_choice == CtrChoice::BeginEndPair);
120 assert(std::ranges::equal(result, in));
121 assert(result.extra_arg1 == arg1);
122 assert(result.extra_arg2 == arg2);
123 assert((in | std::ranges::to<ContainerWithBeginEndPair>(arg1, arg2)) == result);
124 }
125 }
126
127 return true;
128 }
129
main(int,char **)130 int main(int, char**) {
131 test();
132 static_assert(test());
133
134 return 0;
135 }
136