| //===----------------------------------------------------------------------===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| |
| // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 |
| // There is a bug in older versions of Clang that causes trouble with constraints in classes like |
| // `ContainerWithDirectCtr`. |
| // XFAIL: clang-16, apple-clang-15 |
| |
| // template<template<class...> class C, input_range R, class... Args> |
| // constexpr auto to(R&& r, Args&&... args); // Since C++23 |
| |
| #include <ranges> |
| |
| #include <algorithm> |
| #include <array> |
| #include <cassert> |
| #include "container.h" |
| |
| template <class ElementType> |
| struct ContainerWithDirectCtr : Container<ElementType, CtrChoice::DirectCtr> { |
| using Container<ElementType, CtrChoice::DirectCtr>::Container; |
| }; |
| |
| template <std::ranges::input_range Range> |
| ContainerWithDirectCtr(Range&&) -> ContainerWithDirectCtr<std::ranges::range_value_t<Range>>; |
| |
| template <std::ranges::input_range Range> |
| ContainerWithDirectCtr(Range&&, int, char) -> ContainerWithDirectCtr<std::ranges::range_value_t<Range>>; |
| |
| template <class ElementType> |
| struct ContainerWithFromRangeT : Container<ElementType, CtrChoice::FromRangeT> { |
| using Container<ElementType, CtrChoice::FromRangeT>::Container; |
| }; |
| |
| template <std::ranges::input_range Range> |
| ContainerWithFromRangeT(std::from_range_t, Range&&) -> ContainerWithFromRangeT<std::ranges::range_value_t<Range>>; |
| |
| template <std::ranges::input_range Range> |
| ContainerWithFromRangeT(std::from_range_t, Range&&, int, char) -> |
| ContainerWithFromRangeT<std::ranges::range_value_t<Range>>; |
| |
| template <class ElementType> |
| struct ContainerWithBeginEndPair : Container<ElementType, CtrChoice::BeginEndPair> { |
| using Container<ElementType, CtrChoice::BeginEndPair>::Container; |
| }; |
| |
| template <class Iter> |
| ContainerWithBeginEndPair(Iter, Iter) -> ContainerWithBeginEndPair<std::iter_value_t<Iter>>; |
| |
| template <class Iter> |
| ContainerWithBeginEndPair(Iter, Iter, int, char) -> ContainerWithBeginEndPair<std::iter_value_t<Iter>>; |
| |
| constexpr bool test() { |
| std::array in = {1, 2, 3, 4, 5}; |
| int arg1 = 42; |
| char arg2 = 'a'; |
| |
| { // Case 1 -- can construct directly from the given range. |
| { |
| std::same_as<ContainerWithDirectCtr<int>> decltype(auto) result = std::ranges::to<ContainerWithDirectCtr>(in); |
| |
| assert(result.ctr_choice == CtrChoice::DirectCtr); |
| assert(std::ranges::equal(result, in)); |
| assert((in | std::ranges::to<ContainerWithDirectCtr>()) == result); |
| } |
| |
| { // Extra arguments. |
| std::same_as<ContainerWithDirectCtr<int>> decltype(auto) result = |
| std::ranges::to<ContainerWithDirectCtr>(in, arg1, arg2); |
| |
| assert(result.ctr_choice == CtrChoice::DirectCtr); |
| assert(std::ranges::equal(result, in)); |
| assert(result.extra_arg1 == arg1); |
| assert(result.extra_arg2 == arg2); |
| assert((in | std::ranges::to<ContainerWithDirectCtr>(arg1, arg2)) == result); |
| } |
| } |
| |
| { // Case 2 -- can construct from the given range using the `from_range_t` tagged constructor. |
| { |
| std::same_as<ContainerWithFromRangeT<int>> decltype(auto) result = std::ranges::to<ContainerWithFromRangeT>(in); |
| |
| assert(result.ctr_choice == CtrChoice::FromRangeT); |
| assert(std::ranges::equal(result, in)); |
| assert((in | std::ranges::to<ContainerWithFromRangeT>()) == result); |
| } |
| |
| { // Extra arguments. |
| std::same_as<ContainerWithFromRangeT<int>> decltype(auto) result = |
| std::ranges::to<ContainerWithFromRangeT>(in, arg1, arg2); |
| |
| assert(result.ctr_choice == CtrChoice::FromRangeT); |
| assert(std::ranges::equal(result, in)); |
| assert(result.extra_arg1 == arg1); |
| assert(result.extra_arg2 == arg2); |
| assert((in | std::ranges::to<ContainerWithFromRangeT>(arg1, arg2)) == result); |
| } |
| } |
| |
| { // Case 3 -- can construct from a begin-end iterator pair. |
| { |
| std::same_as<ContainerWithBeginEndPair<int>> decltype(auto) result = |
| std::ranges::to<ContainerWithBeginEndPair>(in); |
| |
| assert(result.ctr_choice == CtrChoice::BeginEndPair); |
| assert(std::ranges::equal(result, in)); |
| assert((in | std::ranges::to<ContainerWithBeginEndPair>()) == result); |
| } |
| |
| { // Extra arguments. |
| std::same_as<ContainerWithBeginEndPair<int>> decltype(auto) result = |
| std::ranges::to<ContainerWithBeginEndPair>(in, arg1, arg2); |
| |
| assert(result.ctr_choice == CtrChoice::BeginEndPair); |
| assert(std::ranges::equal(result, in)); |
| assert(result.extra_arg1 == arg1); |
| assert(result.extra_arg2 == arg2); |
| assert((in | std::ranges::to<ContainerWithBeginEndPair>(arg1, arg2)) == result); |
| } |
| } |
| |
| return true; |
| } |
| |
| int main(int, char**) { |
| test(); |
| static_assert(test()); |
| |
| return 0; |
| } |