| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #pragma once | ||
| 2 | |||
| 3 | // [Predefined macros](https://en.cppreference.com/w/cpp/preprocessor/replace#Predefined_macros) | ||
| 4 | #if __cplusplus >= 202302L // since C++23 | ||
| 5 | |||
| 6 | #include <ranges> | ||
| 7 | |||
| 8 | #include <ostream> | ||
| 9 | #include <tuple> | ||
| 10 | |||
| 11 | // See https://en.cppreference.com/w/cpp/utility/apply#Example | ||
| 12 | template <typename... Ts> | ||
| 13 | std::ostream& operator<<(std::ostream& stream, std::tuple<Ts...> const& tuple) { | ||
| 14 | auto f = [&stream](Ts const&... args) { | ||
| 15 | stream << '['; | ||
| 16 | auto n = std::size_t { 0 }; | ||
| 17 | ((stream << args << (++n < sizeof...(Ts) ? ", " : "")), ...); | ||
| 18 | stream << ']'; | ||
| 19 | }; | ||
| 20 | std::apply(f, tuple); | ||
| 21 | return stream; | ||
| 22 | } | ||
| 23 | |||
| 24 | #else // until C++23 | ||
| 25 | |||
| 26 | #pragma message "emulating C++23 ranges" | ||
| 27 | |||
| 28 | #include <boost/range/combine.hpp> | ||
| 29 | #include <boost/tuple/tuple.hpp> | ||
| 30 | #include <boost/tuple/tuple_io.hpp> | ||
| 31 | |||
| 32 | // NOLINTBEGIN(*-concat-nested-namespaces) until C++17 | ||
| 33 | |||
| 34 | namespace std { | ||
| 35 | |||
| 36 | using boost::get; | ||
| 37 | |||
| 38 | namespace ranges { | ||
| 39 | |||
| 40 | namespace views { | ||
| 41 | |||
| 42 | // See [Function Aliases In C++](https://www.fluentcpp.com/2017/10/27/function-aliases-cpp/) | ||
| 43 | template <typename... Args> | ||
| 44 | 34 | inline auto zip(Args && ... args) | |
| 45 | -> decltype(boost::combine(std::forward<Args>(args)...)) { | ||
| 46 | 136 | return boost::combine(std::forward<Args>(args)...); | |
| 47 | } | ||
| 48 | |||
| 49 | } // namespace views | ||
| 50 | |||
| 51 | } // namespace ranges | ||
| 52 | |||
| 53 | } // namespace std | ||
| 54 | |||
| 55 | // NOLINTEND(*-concat-nested-namespaces) | ||
| 56 | |||
| 57 | #endif // C++23 | ||
| 58 |