├── test ├── waf ├── waf-1.7.6 ├── Makefile ├── enumerate.cc ├── wscript ├── zip.cc └── range.cc ├── .gitignore ├── .gitmodules ├── wscript ├── pythonic ├── zip.h ├── range.h ├── enumerate.h └── detail │ ├── traits.h │ ├── util.h │ ├── sequence.h │ ├── range.h │ ├── enumerate.h │ └── zip.h └── README.md /test/waf: -------------------------------------------------------------------------------- 1 | waf-1.7.6 -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | .lock-waf* 3 | .waf-* 4 | bin 5 | test/pythonic 6 | -------------------------------------------------------------------------------- /test/waf-1.7.6: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ignatz/pythonic/HEAD/test/waf-1.7.6 -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "test/gtest"] 2 | path = test/gtest 3 | url = https://github.com/ignatz/gtest.git 4 | -------------------------------------------------------------------------------- /wscript: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import sys, os 3 | 4 | def options(opt): 5 | pass 6 | 7 | def configure(cfg): 8 | pass 9 | 10 | def build(bld): 11 | bld( 12 | target = 'pythonic', 13 | export_includes = '.', 14 | ) 15 | -------------------------------------------------------------------------------- /test/Makefile: -------------------------------------------------------------------------------- 1 | build: configure 2 | ./waf build 3 | 4 | install: configure 5 | ./waf install 6 | 7 | configure: 8 | ./waf configure 9 | 10 | clean: 11 | ./waf clean 12 | 13 | distclean: 14 | ./waf distclean 15 | 16 | .PHONY: build install configure clean distclean 17 | -------------------------------------------------------------------------------- /pythonic/zip.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Copyright (c) 2013, Sebastian Jeltsch (sjeltsch@kip.uni-heidelberg.de) 4 | // Distributed under the terms of the GPLv2 or newer 5 | 6 | #include 7 | 8 | #include "pythonic/detail/zip.h" 9 | 10 | namespace pythonic { 11 | 12 | template 13 | detail::zip_proxy zip(Containers&& ... cs) 14 | { 15 | return detail::zip_proxy( 16 | std::forward(cs)...); 17 | } 18 | 19 | } // pythonic 20 | -------------------------------------------------------------------------------- /pythonic/range.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Copyright (c) 2013, Sebastian Jeltsch (sjeltsch@kip.uni-heidelberg.de) 4 | // Distributed under the terms of the GPLv2 or newer 5 | 6 | #include 7 | 8 | #include "pythonic/detail/range.h" 9 | 10 | namespace pythonic { 11 | 12 | inline 13 | detail::range_proxy 14 | range(int const end) 15 | { 16 | return detail::range_proxy(0, end, 1); 17 | } 18 | 19 | inline 20 | detail::range_proxy 21 | range(int const start, int const end, int const step = 1) 22 | { 23 | return detail::range_proxy(start, end, step); 24 | } 25 | 26 | } // pythonic 27 | -------------------------------------------------------------------------------- /pythonic/enumerate.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Copyright (c) 2013, Sebastian Jeltsch (sjeltsch@kip.uni-heidelberg.de) 4 | // Distributed under the terms of the GPLv2 or newer 5 | 6 | #include 7 | 8 | #include "pythonic/detail/enumerate.h" 9 | 10 | namespace pythonic { 11 | 12 | template 13 | detail::enumerate_proxy 14 | enumerate(Container&& a, int const start = 0) 15 | { 16 | return detail::enumerate_proxy( 17 | std::forward(a), start); 18 | } 19 | 20 | template 21 | char enumerate(Ts&& ...) 22 | { 23 | static_assert(sizeof...(Ts) != 1, 24 | "enumerate(T t) expects one instance t of container type T"); 25 | return char(); 26 | } 27 | 28 | } // pythonic 29 | -------------------------------------------------------------------------------- /pythonic/detail/traits.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Copyright (c) 2013, Sebastian Jeltsch (sjeltsch@kip.uni-heidelberg.de) 4 | // Distributed under the terms of the GPLv2 or newer 5 | 6 | #include 7 | 8 | namespace pythonic { 9 | namespace detail { 10 | 11 | template 12 | struct traits 13 | { 14 | typedef typename Container::size_type size_type; 15 | 16 | typedef typename std::conditional< 17 | std::is_const::value, 18 | typename Container::const_reference, 19 | typename Container::reference 20 | >::type reference; 21 | 22 | typedef typename std::conditional< 23 | std::is_const::value, 24 | typename Container::const_iterator, 25 | typename Container::iterator 26 | >::type iterator; 27 | }; 28 | 29 | } // detail 30 | } // pythonic 31 | -------------------------------------------------------------------------------- /pythonic/detail/util.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Copyright (c) 2013, Sebastian Jeltsch (sjeltsch@kip.uni-heidelberg.de) 4 | // Distributed under the terms of the GPLv2 or newer 5 | 6 | #include 7 | 8 | namespace pythonic { 9 | namespace detail { 10 | 11 | template 12 | struct pack {}; 13 | 14 | 15 | template 16 | inline 17 | void noop(T&& ...) 18 | {} 19 | 20 | 21 | template 22 | inline 23 | Return sum() 24 | { 25 | return 0; 26 | } 27 | 28 | template 29 | inline 30 | Return sum(T const& t, Ts const& ... ts) 31 | { 32 | return t + sum(ts...); 33 | } 34 | 35 | template 36 | int sign(T const t) 37 | { 38 | return (t < T(0)) ? -1 : 1; 39 | } 40 | 41 | } // detail 42 | } // pythonic 43 | -------------------------------------------------------------------------------- /pythonic/detail/sequence.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Copyright (c) 2013, Sebastian Jeltsch (sjeltsch@kip.uni-heidelberg.de) 4 | // Distributed under the terms of the GPLv2 or newer 5 | 6 | #include 7 | 8 | #include "pythonic/detail/util.h" 9 | 10 | namespace pythonic { 11 | namespace detail { 12 | 13 | template 14 | struct build_sequence; 15 | 16 | template 17 | struct build_sequence, Start, Arg, Args...> 18 | { 19 | typedef typename build_sequence< 20 | pack, 21 | Start+1, Args...>::type type; 22 | }; 23 | 24 | template 25 | struct build_sequence, Start> 26 | { 27 | typedef pack type; 28 | }; 29 | 30 | 31 | template 32 | struct sequence 33 | { 34 | typedef typename build_sequence, 0, Args...>::type type; 35 | }; 36 | 37 | } // detail 38 | } // pythonic 39 | -------------------------------------------------------------------------------- /test/enumerate.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "pythonic/enumerate.h" 4 | 5 | using namespace pythonic; 6 | 7 | TEST(Enumerate, Simple) 8 | { 9 | std::vector vec(10, 42); 10 | 11 | for (int probe : std::vector {0, -1337, 42}) { 12 | for (auto v : enumerate(vec, probe)) { 13 | ASSERT_EQ(probe++, v.first); 14 | ASSERT_EQ(42, v.second); 15 | } 16 | } 17 | } 18 | 19 | TEST(Enumerate, Const) 20 | { 21 | std::vector vec(10, 42); 22 | auto const& ref = vec; 23 | int probe; 24 | 25 | probe = 0; 26 | for (auto v : enumerate(ref)) { 27 | ASSERT_EQ(probe++, v.first); 28 | ASSERT_EQ(42, v.second); 29 | } 30 | 31 | probe = 0; 32 | for (auto const& v : enumerate(ref)) { 33 | ASSERT_EQ(probe++, v.first); 34 | ASSERT_EQ(42, v.second); 35 | } 36 | } 37 | 38 | TEST(Enumerate, RValue) 39 | { 40 | int probe = 0; 41 | for (auto const& v : enumerate(std::vector (10, 42))) { 42 | ASSERT_EQ(probe++, v.first); 43 | ASSERT_EQ(42, v.second); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /test/wscript: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import sys, os 3 | 4 | components = ['gtest', '..'] 5 | recurse = lambda ctx : map(lambda proj: ctx.recurse(proj), components) 6 | 7 | def options(opt): 8 | opt.load('g++') 9 | opt.load('boost') 10 | recurse(opt) 11 | 12 | def configure(cfg): 13 | cfg.load('g++') 14 | cfg.load('boost') 15 | recurse(cfg) 16 | 17 | cfg.check_boost( 18 | lib='system', 19 | uselib_store='BOOST') 20 | 21 | def build(bld): 22 | recurse(bld) 23 | 24 | bld( 25 | target = 'main', 26 | features = 'cxx cxxprogram', 27 | source = bld.path.ant_glob('*.cc'), 28 | use = ['pythonic', 'gtest', 'BOOST'], 29 | install_path = 'bin', 30 | cxxflags = [ 31 | '-g', 32 | '-O0', 33 | '-std=c++0x', 34 | '-Wall', 35 | '-Wextra', 36 | '-pedantic', 37 | ], 38 | includes = '.', 39 | ) 40 | -------------------------------------------------------------------------------- /test/zip.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "pythonic/zip.h" 4 | 5 | #define UNUSED(x) static_cast(x) 6 | 7 | using namespace pythonic; 8 | 9 | TEST(Zip, Simple) 10 | { 11 | std::vector vec0(10, 42); 12 | std::vector vec1(10, 5); 13 | 14 | for(auto v : zip(vec0, vec1)) { 15 | ASSERT_EQ(42, std::get<0>(v)); 16 | ASSERT_EQ(42, v.first); // special case for 2 containers 17 | ASSERT_EQ( 5, std::get<1>(v)); 18 | ASSERT_EQ( 5, v.second); // special case for 2 containers 19 | } 20 | } 21 | 22 | TEST(Zip, Const) 23 | { 24 | std::vector vec0(10, 42); 25 | std::vector const& ref = vec0; 26 | for(auto v : zip(vec0, ref)) { 27 | ASSERT_EQ(42, std::get<0>(v)); 28 | ASSERT_EQ(42, std::get<1>(v)); 29 | } 30 | } 31 | 32 | TEST(Zip, Empty) 33 | { 34 | for(auto v : zip()) { 35 | UNUSED(v); 36 | ASSERT_TRUE(false); 37 | } 38 | } 39 | 40 | #ifndef PYTHONIC_SAFE_ZIP 41 | TEST(Zip, VariableLength) 42 | { 43 | std::vector vec0(10, 42); 44 | std::vector vec_long(100, 5); 45 | size_t cnt = 0; 46 | for(auto v : zip(vec0, vec_long)) { 47 | ASSERT_EQ(42, std::get<0>(v)); 48 | ASSERT_EQ( 5, std::get<1>(v)); 49 | cnt++; 50 | } 51 | ASSERT_EQ(vec0.size(), cnt); 52 | } 53 | #endif 54 | -------------------------------------------------------------------------------- /test/range.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "pythonic/range.h" 4 | #include "pythonic/zip.h" 5 | #include "pythonic/enumerate.h" 6 | 7 | using namespace pythonic; 8 | using namespace std; 9 | 10 | int const last = 1337; 11 | 12 | TEST(Range, Simple) 13 | { 14 | vector> ranges { 15 | { 0, 11, 1 }, 16 | { 0, 11, 2 }, 17 | { 0, 11, 3 }, 18 | {-1, 11, 2 }, 19 | {-1,-20,-1 }, 20 | {-3,-20,-3 } 21 | }; 22 | vector> expect { 23 | {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, last}, 24 | {0, 2, 4, 6, 8, 10, last}, 25 | {0, 3, 6, 9, last}, 26 | {-1, 1, 3, 5, 7, 9, last}, 27 | {-1, -2, -3, -4, -5, -6, -7, -8, -9, -10, 28 | -11, -12, -13, -14, -15, -16, -17, -18, -19, last}, 29 | {-3, -6, -9, -12, -15, -18, last} 30 | }; 31 | 32 | int s = -10; 33 | for (auto const& r : range(-10, 20, 3)) 34 | { 35 | ASSERT_EQ(s, r); 36 | s += 3; 37 | } 38 | 39 | for (auto const& v : zip(ranges, expect)) 40 | { 41 | for (auto const& probe : enumerate( 42 | range(std::get<0>(v)[0], std::get<0>(v)[1], std::get<0>(v)[2]))) 43 | { 44 | ASSERT_EQ(std::get<1>(v)[probe.first], probe.second); 45 | } 46 | } 47 | } 48 | 49 | TEST(Range, Enumerate) 50 | { 51 | std::vector vec { 3,6,476,4,2,4,23,123,13,4,345,346,456 }; 52 | 53 | int const start = -1; 54 | auto en = enumerate(vec, start).begin(); 55 | auto z = zip(range(start, vec.size() + start), vec).begin(); 56 | for (size_t ii = 0; ii< vec.size() ; ++ii) 57 | { 58 | ASSERT_EQ(en->first, std::get<0>(*z)); 59 | ASSERT_EQ(en->second, std::get<1>(*z)); 60 | 61 | ++en; 62 | ++z; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /pythonic/detail/range.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Copyright (c) 2013, Sebastian Jeltsch (sjeltsch@kip.uni-heidelberg.de) 4 | // Distributed under the terms of the GPLv2 or newer 5 | 6 | #include 7 | 8 | #include 9 | #include "pythonic/detail/util.h" 10 | 11 | namespace pythonic { 12 | namespace detail { 13 | 14 | template 15 | struct const_range_iterator : 16 | public boost::iterator_facade< 17 | const_range_iterator, 18 | T const, 19 | boost::incrementable_traversal_tag> 20 | { 21 | public: 22 | const_range_iterator(T const current, T const step) 23 | : current(current), step(step) 24 | {} 25 | 26 | private: 27 | friend class boost::iterator_core_access; 28 | 29 | bool equal(const_range_iterator const& other) const 30 | { 31 | return current == other.current; 32 | } 33 | 34 | void increment() 35 | { 36 | current += step; 37 | } 38 | 39 | T const& 40 | dereference() const 41 | { 42 | return current; 43 | } 44 | 45 | T current; 46 | T const step; 47 | }; 48 | 49 | 50 | template 51 | class range_proxy 52 | { 53 | public: 54 | typedef size_t size_type; 55 | typedef const_range_iterator iterator; 56 | typedef const_range_iterator const_iterator; 57 | typedef typename std::add_const::type& reference; 58 | typedef typename std::add_const::type& const_reference; 59 | 60 | range_proxy(T start, T end, T step) : 61 | m_start(start), m_end(end), m_step(step) 62 | {} 63 | 64 | const_range_iterator begin() 65 | { 66 | return const_range_iterator(m_start, m_step); 67 | }; 68 | 69 | const_range_iterator end() 70 | { 71 | T last (m_end-sign(m_step)); 72 | return const_range_iterator(last - (last-m_start)%m_step, 0); 73 | }; 74 | 75 | private: 76 | T const m_start; 77 | T const m_end; 78 | T const m_step; 79 | }; 80 | 81 | } // detail 82 | } // pythonic 83 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | `pythonic++` - A small `C++` convenience library 2 | ================================================ 3 | 4 | `pythonic++` brings some python-style programming to `C++` for ease, fun and 5 | more expressive code (see examples below). 6 | 7 | `enumerate()` 8 | ------------- 9 | 10 | The `enumerate(Container [, start])` function can be used to count the 11 | iterations over an STL conform container. Optionally, the value to start counting 12 | from can be provided. 13 | 14 | #include 15 | #include 16 | #include "pythonic/enumerate.h" 17 | using namespace pythonic; 18 | 19 | // ... 20 | 21 | typedef std::vector vec; 22 | 23 | for (auto v : enumerate(vec {0, -1337, 42})) 24 | { 25 | std::cout << v.first << " " << v.second << std::endl; 26 | } 27 | 28 | // ... 29 | 30 | 31 | `zip()` 32 | ------- 33 | 34 | The `zip([Container, ...])` function can be used to iterate over several 35 | containers in lockstep. The number of iterations is determined by the length 36 | of the shortest container. 37 | 38 | #include 39 | #include 40 | #include "pythonic/zip.h" 41 | using namespace pythonic; 42 | 43 | // ... 44 | 45 | std::map m; 46 | 47 | // ... 48 | 49 | std::vector keys(m.size()); 50 | std::vector values(m.size()); 51 | 52 | for (auto v : zip(m, keys, values)) 53 | { 54 | std::get<1>(v) = std::get<0>(v).first; 55 | std::get<2>(v) = std::get<0>(v).second; 56 | } 57 | 58 | // ... 59 | 60 | In the example, two vectors are filled with the keys and values from a map. 61 | 62 | 63 | `range()` 64 | --------- 65 | 66 | The functions `range(end)` and `range(start, end [, step])` can be used as 67 | iterateable representations of ranges. 68 | 69 | 70 | #include 71 | #include "pythonic/zip.h" 72 | using namespace pythonic; 73 | 74 | // ... 75 | 76 | std::vector vec = {324,5,435,12,3,23,4}; 77 | 78 | for (auto const& v : zip(range(vec.size()), vec)) 79 | { 80 | std::cout << std::get<0>(v) << " " << std::get<1>(v) << std::endl; 81 | } 82 | 83 | // ... 84 | 85 | In this example, we implemented `enumerate()` by means of `range` and `zip`. 86 | 87 | Requirements 88 | ------------ 89 | 90 | The library requires a modern compiler supporting `C++11`. 91 | 92 | 93 | Licensing 94 | --------- 95 | Copyright (c) 2013, Sebastian Jeltsch (sjeltsch@kip.uni-heidelberg.de) 96 | 97 | Distributed under the terms of the GPLv2 or newer. 98 | -------------------------------------------------------------------------------- /pythonic/detail/enumerate.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Copyright (c) 2013, Sebastian Jeltsch (sjeltsch@kip.uni-heidelberg.de) 4 | // Distributed under the terms of the GPLv2 or newer 5 | 6 | #include 7 | #include 8 | 9 | #include 10 | 11 | #include "pythonic/detail/traits.h" 12 | 13 | namespace pythonic { 14 | namespace detail { 15 | 16 | template 17 | struct enumerate_iterator : 18 | public boost::iterator_facade< 19 | enumerate_iterator, 20 | std::pair::reference>, 21 | boost::incrementable_traversal_tag, 22 | std::pair::reference> 23 | > 24 | { 25 | public: 26 | enumerate_iterator( 27 | typename traits::iterator it, 28 | int const start = 0) 29 | : it(it), cnt(start) 30 | {} 31 | 32 | private: 33 | friend class boost::iterator_core_access; 34 | 35 | typedef std::pair< 36 | int, typename traits::reference> reference; 37 | 38 | bool equal(enumerate_iterator const& other) const 39 | { 40 | return it == other.it; 41 | } 42 | 43 | void increment() 44 | { 45 | ++it; 46 | ++cnt; 47 | } 48 | 49 | reference 50 | dereference() const 51 | { 52 | return reference(cnt, *it); 53 | } 54 | 55 | typename traits::iterator it; 56 | int cnt; 57 | }; 58 | 59 | 60 | template 61 | struct enumerate_proxy 62 | { 63 | private: 64 | typedef typename std::remove_reference::type type; 65 | 66 | public: 67 | typedef size_t size_type; 68 | typedef enumerate_iterator iterator; 69 | typedef enumerate_iterator::type> const_iterator; 71 | typedef type& reference; 72 | typedef typename std::add_const::type& const_reference; 73 | 74 | template 75 | enumerate_proxy(T&& data, int const start = 0) : 76 | container(std::forward(data)), start(start) 77 | {} 78 | 79 | enumerate_iterator begin() 80 | { 81 | return enumerate_iterator(container.begin(), start); 82 | }; 83 | 84 | enumerate_iterator end() 85 | { 86 | return enumerate_iterator(container.end(), -1); 87 | }; 88 | 89 | private: 90 | // if Container is passed by rvalue, move it here. 91 | // Otherwise, use the lvalue reference. 92 | typename std::conditional< 93 | std::is_rvalue_reference::value, 94 | type, type&>::type container; 95 | int const start; 96 | }; 97 | 98 | } // detail 99 | } // pythonic 100 | -------------------------------------------------------------------------------- /pythonic/detail/zip.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Copyright (c) 2013, Sebastian Jeltsch (sjeltsch@kip.uni-heidelberg.de) 4 | // Distributed under the terms of the GPLv2 or newer 5 | 6 | #include 7 | #include 8 | 9 | #include 10 | 11 | #include "pythonic/detail/util.h" 12 | #include "pythonic/detail/sequence.h" 13 | #include "pythonic/detail/traits.h" 14 | 15 | namespace pythonic { 16 | namespace detail { 17 | 18 | // allow access via first & second if two containers are zipped 19 | template 20 | struct zip_tuple 21 | { 22 | typedef std::tuple type; 23 | }; 24 | 25 | template 26 | struct zip_tuple 27 | { 28 | typedef std::pair type; 29 | }; 30 | 31 | 32 | template 33 | struct zip_iterator : 34 | public boost::iterator_facade< 35 | zip_iterator, 36 | typename zip_tuple::reference ...>::type, 37 | boost::incrementable_traversal_tag, 38 | typename zip_tuple::reference ...>::type 39 | > 40 | { 41 | public: 42 | typedef typename zip_tuple::reference ...>::type reference; 44 | typedef typename zip_tuple::reference>::type ...>::type const_reference; 46 | 47 | zip_iterator(typename traits::iterator ... its) 48 | : its(its...) 49 | {} 50 | 51 | private: 52 | friend class boost::iterator_core_access; 53 | 54 | bool equal(zip_iterator const& rhs) const 55 | { 56 | #ifdef PYTHONIC_SAFE_ZIP // safe_zip expects containers of equal length 57 | return its == rhs.its; 58 | #else // unsafe zip, truncate to length of shortest container 59 | return equal_helper(rhs, typename sequence::type ()); 60 | #endif 61 | } 62 | 63 | void increment() 64 | { 65 | increment_helper(typename sequence::type ()); 66 | } 67 | 68 | reference dereference() const 69 | { 70 | return dereference_helper(typename sequence::type ()); 71 | } 72 | 73 | template 74 | reference dereference_helper(pack const&) const 75 | { 76 | return reference(*std::get(its)...); 77 | } 78 | 79 | template 80 | void increment_helper(pack const&) 81 | { 82 | noop(++std::get(its)...); 83 | } 84 | 85 | template 86 | bool equal_helper( 87 | zip_iterator const& rhs, 88 | pack const&) const 89 | { 90 | return sum(std::get(its) == std::get(rhs.its)...); 91 | } 92 | 93 | typename zip_tuple::iterator ...>::type its; 94 | }; 95 | 96 | 97 | template 98 | class zip_proxy 99 | { 100 | public: 101 | typedef size_t size_type; 102 | typedef zip_iterator::type...> iterator; 104 | typedef zip_iterator::type>::type ...> const_iterator; 106 | typedef typename iterator::reference reference; 107 | typedef typename iterator::const_reference const_reference; 108 | 109 | template 110 | zip_proxy(Ts&& ... ts) : 111 | containers(std::forward(ts)...) 112 | {} 113 | 114 | iterator begin() 115 | { 116 | return begin_helper(typename sequence::type ()); 117 | }; 118 | 119 | iterator end() 120 | { 121 | return end_helper(typename sequence::type ()); 122 | }; 123 | 124 | private: 125 | template 126 | iterator begin_helper(pack const&) 127 | { 128 | return iterator(std::begin(std::get(containers))...); 129 | } 130 | 131 | template 132 | iterator end_helper(pack const&) 133 | { 134 | return iterator(std::end(std::get(containers))...); 135 | } 136 | 137 | // if Container is passed by rvalue, move it here. 138 | // Otherwise, use the lvalue reference. 139 | typename std::tuple< 140 | typename std::conditional< 141 | std::is_rvalue_reference::value, 142 | typename std::remove_reference::type, 143 | typename std::remove_reference::type& 144 | >::type ... 145 | > containers; 146 | }; 147 | 148 | // specialization for empty zip with always begin() == end() 149 | template<> 150 | struct zip_proxy<> 151 | { 152 | public: 153 | char const* begin() const { return nullptr; }; 154 | char const* end() const { return nullptr; }; 155 | }; 156 | 157 | } // detail 158 | } // pythonic 159 | --------------------------------------------------------------------------------