読者です 読者をやめる 読者になる 読者になる

foreach

C++

最新はこちら


BOOST_FOREACHを作ってみました


正式リリース前のBOOST_FOREACHのzip内にあるpptに作り方書いてるんですね

namespace shand { namespace foreach_detail {

struct static_any_base {
    operator bool() const { return  false; }
};

template <class Type>
struct static_any : static_any_base {
    static_any(const Type& item) : item_(item) {}
    mutable Type item_;
};

typedef const static_any_base& static_any_t;


template <class Type>
inline Type& static_any_cast(static_any_t value)
{
    return static_cast<const static_any<Type>&>(value).item_;
}


// array
template <class Type, int Size>
inline static_any<Type*> begin(Type (&ar)[Size], void*)
{
    return ar;
}

template <class Type, int Size>
inline static_any<Type*> end(Type (&ar)[Size], void*)
{
    return ar + Size;
}

template <class Type, int Size>
inline void next(static_any_t cur, Type (&)[Size], void*)
{
    ++static_any_cast<Type*>(cur);
}


template <class Type, int Size>
inline Type& extract(static_any_t cur, Type (&)[Size], void*)
{
    return *static_any_cast<Type*>(cur);
}

template <class Type, int Size>
inline bool done(static_any_t cur, static_any_t end, Type (&)[Size], void*)
{
    return static_any_cast<Type*>(cur) == static_any_cast<Type*>(end);
}


// STL Container
struct sfinae_types {
    typedef char yes;
    typedef struct { char arr[2]; } no;
};

template <class Type>
struct is_stl : sfinae_types {
private:
    template <class Type>
    static yes check(typename Type::iterator*);

    template<class>
    static no check(...);
public:
    enum { value = sizeof(yes)==sizeof(check<Type>(0)) };
};


// enable_if
template <bool, class Type = void>
struct enable_if_c {
    typedef Type type;
};

template <class Type>
struct enable_if_c<false, Type> {};

template <class Cond, class Type = void> 
struct enable_if : public enable_if_c<Cond::value, Type> {};



template <class Type>
inline static_any<typename Type::iterator> begin(Type& container, typename enable_if<is_stl<Type> >::type*)
{
    return container.begin();
}

template <class Type>
inline static_any<typename Type::iterator> end(Type& container, typename enable_if<is_stl<Type> >::type*)
{
    return container.end();
}

template <class Type>
inline void next(static_any_t cur, Type&, typename enable_if<is_stl<Type> >::type*)
{
    ++static_any_cast<typename Type::iterator>(cur);
}

template <class Type>
inline typename Type::reference extract(static_any_t cur, Type&, typename enable_if<is_stl<Type> >::type*)
{
    return *static_any_cast<typename Type::iterator>(cur);
}


template <class Type>
inline bool done(static_any_t cur, static_any_t end, Type&, typename enable_if<is_stl<Type> >::type*)
{
    typedef typename Type::iterator Iter;
    return static_any_cast<Iter>(cur) == static_any_cast<Iter>(end);
}

// foreach macro
#define SHAND_FOREACH(VAR, COL)                                                                                 \
        if       (shand::foreach_detail::static_any_t _cur = shand::foreach_detail::begin(COL, 0) ) {}          \
        else if  (shand::foreach_detail::static_any_t _end = shand::foreach_detail::end(COL, 0) ) {}            \
        else for (bool _continue = true;                                                                        \
                  _continue && !shand::foreach_detail::done(_cur, _end, COL, 0);                                \
                  _continue ? shand::foreach_detail::next(_cur, COL, 0) : (void)&COL)                           \
                 if      ((_continue = false) == true) {}                                                       \
                 else for (VAR = shand::foreach_detail::extract(_cur, COL, 0); !_continue; _continue = true)

#define foreach SHAND_FOREACH

}} // namespace shand::foreach_detail


配列

#include <iostream>
#include <shand/foreach.hpp>

using namespace std;

int main()
{
    int ar[3] = {3, 1, 4};

    foreach (int value, ar) {
        cout << value << endl;
    }
    return 0;
}


コンテナ(iterator型とreference型とbegin(), end()持ってればいい)

#include <iostream>
#include <vector>
#include <shand/foreach.hpp>

using namespace std;

int main()
{
    vector<int> v;

    v.push_back(3);
    v.push_back(1);
    v.push_back(4);

    foreach (int value, v) {
        cout << value << endl;
    }
    return 0;
}


参照も可能

foreach (int& value, v) {
    ++value;
}


break/continueも可能

foreach (int value, v) {
    break;
}

※これが気に入らない人は消してください

#define foreach SHAND_FOREACH

※組み込み型以外のループには(const)参照を使いましょう
for文よりちょっと遅い程度で済みます

foreach (const Widget& widget, v)
    ...


ライブラリまとめ