| 71 | } |
| 72 | |
| 73 | TEST(Zip, TupleTypes) { |
| 74 | char arr[3]; |
| 75 | const std::string const_arr[3]; |
| 76 | for (auto tuple : |
| 77 | Zip(arr, // 1. mutable lvalue range |
| 78 | const_arr, // 2. const lvalue range |
| 79 | std::vector<float>{}, // 3. rvalue range |
| 80 | std::vector<bool>{}, // 4. rvalue range dereferencing to non ref |
| 81 | Enumerate<int>)) { // 6. Enumerate |
| 82 | // (const lvalue range dereferencing to non ref) |
| 83 | static_assert( |
| 84 | std::is_same_v<decltype(tuple), |
| 85 | std::tuple<char&, // 1. mutable lvalue ref binding |
| 86 | const std::string&, // 2. const lvalue ref binding |
| 87 | float&, // 3. mutable lvalue ref binding |
| 88 | std::vector<bool>::reference, // 4. by-value non ref |
| 89 | // binding (thanks STL) |
| 90 | int // 5. by-value non ref binding |
| 91 | // (that's fine they're just ints) |
| 92 | >>); |
| 93 | } |
| 94 | |
| 95 | static size_t max_count; |
| 96 | static size_t count = 0; |
| 97 | |
| 98 | struct Counted { |
| 99 | static void increment_count() { |
| 100 | ++count; |
| 101 | EXPECT_LE(count, max_count); |
| 102 | } |
| 103 | |
| 104 | Counted() { increment_count(); } |
| 105 | Counted(Counted&&) { increment_count(); } |
| 106 | |
| 107 | ~Counted() { --count; } |
| 108 | |
| 109 | Counted(const Counted&) = delete; |
| 110 | Counted& operator=(const Counted&) = delete; |
| 111 | Counted& operator=(Counted&&) = delete; |
| 112 | }; |
| 113 | |
| 114 | { |
| 115 | max_count = 3; |
| 116 | const Counted const_arr[3]; |
| 117 | EXPECT_EQ(count, 3); |
| 118 | |
| 119 | for (auto [e] : Zip(const_arr)) { |
| 120 | // Putting a const reference to range into Zip results in no copies and the |
| 121 | // corresponding tuple element will also be a const reference |
| 122 | EXPECT_EQ(count, 3); |
| 123 | static_assert(std::is_same_v<decltype(e), const Counted&>); |
| 124 | } |
| 125 | EXPECT_EQ(count, 3); |
| 126 | } |
| 127 | |
| 128 | { |
| 129 | max_count = 3; |
| 130 | Counted arr[3]; |