c++foreachboost-foreach

BOOST_FOREACH without Boost?


Is there an implementation of a "for each" macro like BOOST_FOREACH that doesn't need Boost?


Solution

  • I've made one.
    It should work with C++11 r-value references in GCC and MSVC, but I haven't tested it well so if there's any errors please let me know.
    Edit: I added support for strings.

    #include <iterator>
    #include <utility>
    
    #define foreach(v, r) \
        if (fe_detail::any const &fe_r_ = \
            fe_detail::make_range(r)) { } else \
        if (fe_detail::any const &fe_b_ = \
            fe_detail::begin(fe_r_, ((void)0, 1) ? NULL : fe_detail::twrap(r))) { } else \
        if (fe_detail::equal( \
            fe_b_, \
            fe_detail::end(fe_r_, ((void)0, 1) ? NULL : fe_detail::twrap(r)), \
            ((void)0, 1) ? NULL : fe_detail::twrap(r))) { } else \
        for (bool fe_c_ = false; \
            !fe_c_ && !fe_detail::equal( \
                fe_b_, \
                fe_detail::end(fe_r_, ((void)0, 1) ? NULL : fe_detail::twrap(r)), \
                ((void)0, 1) ? NULL : fe_detail::twrap(r)); \
            fe_detail::advance(fe_b_, 1, ((void)0, 1) ? NULL : fe_detail::twrap(r))) \
        for (v = (fe_detail::move(*fe_detail::iter(fe_b_, ((void)0, 1) ? NULL : fe_detail::twrap(r)))); \
            fe_c_ = !fe_c_; )
    
    namespace fe_detail
    {
        // Container traits
        template<class C, class It> struct CT
        {
            typedef It It;
            static It begin(C &c) { return c.begin(); }
            static It end(C &c) { return c.end(); }
        };
    
        // Range traits
        template<class R> struct RT : public CT<R, typename R::iterator> { };
        template<class R> struct RT<R const> : public CT<R const, typename R::const_iterator> { };
        template<class R> struct RT<R &> : public RT<R> { };
    
        template<class T, bool B = T::value> struct enable_if;
        template<class T> struct enable_if<T, true> { typedef T type; };
    
        template<class T> struct is_char { static bool const value = false; };
        template<class T> struct is_char<T const> : public is_char<T> { };
        template<class T> struct is_char<T volatile> : public is_char<T> { };
        template<> struct is_char<char> { static bool const value = true; };
        template<> struct is_char<wchar_t> { static bool const value = true; };
    
        template<class Ch> struct RT<Ch *> : enable_if<is_char<Ch> >
        {
            typedef Ch *It;
            static It begin(It a) { return &a[0]; }
            static It end(It a) { return &a[std::char_traits<Ch>::length(a)]; }
        };
    
        template<class R, size_t N> struct RT<R[N]>
        {
            typedef R *It;
            static It begin(It a) { return &a[0]; }
            static It end(It a) { return &a[N - (((void)0, is_char<R>::value) ? 1 : 0)]; }
        };
    
        template<class It> struct RT<std::pair<It, It> >
        {
            typedef It It;
            static It begin(std::pair<It, It> const a) { return a.first; }
            static It end(std::pair<It, It> const a) { return a.second; }
        };
    
        struct any { operator bool() const { return false; } };
    
        template<class T> struct type_wrap { type_wrap(bool = false) { } };
    
        template<class T> class wrap : public any
        { wrap &operator =(wrap const &); public: mutable T v; wrap(T v) : any(), v(v) { } };
    
        template<class T> class wrap<T const> : public any
        { wrap &operator =(wrap const &); public: T const v; wrap(T const v) : any(), v(v) { } };
    
        template<class T, size_t N> class wrap<T[N]> : public any
        { wrap &operator =(wrap const &); public: T (&v)[N]; wrap(T (&v)[N]) : any(), v(v) { } };
    
        template<class T> class wrap<T const &> : public wrap<T const>
        { wrap &operator =(wrap const &); public: wrap(T const &v) : wrap<T const>(v) { } };
    
        template<class T, size_t N> wrap<T[N]> make_range(T (&r)[N]) { return r; }
        template<class T, size_t N> type_wrap<T[N]> twrap(T (&r)[N]) { throw 0; }
        template<class It> type_wrap<std::pair<It, It> > twrap(std::pair<It, It> const &p) { throw 0; }
    
    #if defined(_MSC_VER) && _MSC_VER >= 1600 || defined(__RVALUE_REFERENCE) || defined(__GXX_EXPERIMENTAL_CXX0X__)
        template<class R> struct RT<R &&> : public RT<R> { };
        template<class T> class wrap<T &&> : public wrap<T> { public: wrap(T &&v) : wrap<T>(std::move(v)) { } };
    
        template<class R> wrap<R &&> make_range(R &&r) { return wrap<R &&>(std::forward<R>(r)); }
        template<class R> type_wrap<R> twrap(R &&) { throw 0; }
        using std::move;
    #else
        template<class R> wrap<R> make_range(R &r) { return r; }
        template<class R> wrap<R const &> make_range(R const &r) { return r; }
    
        template<class R> type_wrap<R> twrap(R &) { throw 0; }
        template<class R> type_wrap<R const &> twrap(R const &) { throw 0; }
        template<class T> T &move(T &v) { return v; }
        template<class T> T const &move(T const &v) { return v; }
    #endif
    
        template<class R> wrap<typename RT<R>::It> begin(any const &r, type_wrap<R>)
        { return RT<R>::begin(static_cast<wrap<R> const &>(r).v); }
    
        template<class R> wrap<typename RT<R>::It>   end(any const &r, type_wrap<R>)
        { return RT<R>::end  (static_cast<wrap<R> const &>(r).v); }
    
        template<class R> bool equal(any const &i, any const &j, type_wrap<R>)
        { return static_cast<wrap<typename RT<R>::It> const &>(i).v == static_cast<wrap<typename RT<R>::It> const &>(j).v; }
    
        template<class R> void advance(any const &i, typename std::iterator_traits<typename RT<R>::It>::difference_type const d, type_wrap<R>)
        { return std::advance(static_cast<wrap<typename RT<R>::It> const &>(i).v, d); }
    
        template<class R> typename RT<R>::It &iter(any const &i, type_wrap<R>)
        { return static_cast<wrap<typename RT<R>::It> const &>(i).v; }  
    }
    

    You can use it like:

    #include <vector>
    #include <iostream>
    
    std::vector<int> make_vect()
    {
        std::vector<int> v;
        v.push_back(5);
        v.push_back(8);
        v.push_back(10);
        return v;
    }
    
    int main()
    {
        foreach (int c, make_vect())
        {
            std::cout << c << std::endl;
        }
    }