• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
10 
11 // ITER_TRAITS(I)
12 
13 // -- If the qualified-id ITER_TRAITS(I)::iterator_concept is valid and names a
14 //   type, then ITER_CONCEPT(I) denotes that type.
15 // (1.2) -- Otherwise, if the qualified-id ITER_TRAITS(I)::iterator_category is
16 // valid and names a type, then ITER_CONCEPT(I) denotes that type.
17 // (1.3) -- Otherwise, if iterator_traits<I> names a specialization generated
18 // from the primary template, then ITER_CONCEPT(I) denotes
19 // random_access_iterator_tag.
20 // (1.4) -- Otherwise, ITER_CONCEPT(I) does not denote a type.
21 
22 #include "test_macros.h"
23 
24 #include <__type_traits/is_valid_expansion.h>
25 #include <iterator>
26 
27 struct OtherTag : std::input_iterator_tag {};
28 struct OtherTagTwo : std::output_iterator_tag {};
29 
30 struct MyIter {
31   using iterator_category = std::random_access_iterator_tag;
32   using iterator_concept = int;
33   using value_type = char;
34   using difference_type = std::ptrdiff_t;
35   using pointer = char*;
36   using reference = char&;
37 };
38 
39 struct MyIter2 {
40   using iterator_category = OtherTag;
41   using value_type = char;
42   using difference_type = std::ptrdiff_t;
43   using pointer = char*;
44   using reference = char&;
45 };
46 
47 struct MyIter3 {};
48 
49 struct Empty {};
50 struct EmptyWithSpecial {};
51 template <>
52 struct std::iterator_traits<MyIter3> {
53   using iterator_category = OtherTagTwo;
54   using value_type = char;
55   using difference_type = std::ptrdiff_t;
56   using pointer = char*;
57   using reference = char&;
58 };
59 
60 template <>
61 struct std::iterator_traits<EmptyWithSpecial> {
62   // empty non-default.
63 };
64 
main(int,char **)65 int main(int, char**) {
66   // If the qualified-id ITER_TRAITS(I)::iterator_concept is valid and names a type,
67   // then ITER_CONCEPT(I) denotes that type.
68   {
69 #if TEST_STD_VER > 17
70     ASSERT_SAME_TYPE(std::_ITER_CONCEPT<char*>, std::contiguous_iterator_tag);
71 #endif
72     ASSERT_SAME_TYPE(std::_ITER_CONCEPT<MyIter>, int);
73   }
74   // Otherwise, if the qualified-id ITER_TRAITS(I)::iterator_category is valid
75   // and names a type, then ITER_CONCEPT(I) denotes that type.
76   {
77     ASSERT_SAME_TYPE(std::_ITER_CONCEPT<MyIter2>, OtherTag);
78     ASSERT_SAME_TYPE(std::_ITER_CONCEPT<MyIter3>, OtherTagTwo);
79   }
80   // FIXME - This requirement makes no sense to me. Why does an empty type with
81   // an empty default iterator_traits get a category of random?
82   {
83     ASSERT_SAME_TYPE(std::_ITER_CONCEPT<Empty>, std::random_access_iterator_tag);
84   }
85   {
86     static_assert(!std::_IsValidExpansion<std::_ITER_CONCEPT, EmptyWithSpecial>::value, "");
87   }
88 
89   return 0;
90 }
91