xref: /llvm-project/libcxx/test/std/ranges/range.utility/range.utility.conv/to_deduction.pass.cpp (revision 0ad663ead1242e908a8c5005f35e72747d136a3b)
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