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

タプルを展開するfor_each

C++

最近タプルをよく使うのですが、タプルのリストを走査する際、
タプルの要素に名前を付けるために変数を作るのがめんどくさいです。
たとえばこんな感じ:

std::vector<fusion::vector<int, char> > v;
boost::for_each(v, [](fusion::vector<int, char> t) {
    const int  x = fusion::at_c<0>(t);
    const char c = fusion::at_c<1>(t);
    // use...
});

for_eachによって関数が呼び出される際にタプルを展開してくれれば、
パラメータとして各型のデータが渡されると共に名前も同時に付けることができるので便利です。

std::vector<fusion::vector<int, char> > v;
fused_for_each(v, [](int x, char c) {
    // use...
});


fusion::fusedがあれば簡単に実装できそうだったのでやってみました。


fused_for_each.hpp

#ifndef SHAND_FUSED_FOR_EACH_INCLUDE
#define SHAND_FUSED_FOR_EACH_INCLUDE

#include <boost/range.hpp>
#include <boost/fusion/include/make_fused.hpp>

namespace shand {

template <class InputIterator, class F>
void fused_for_each(InputIterator first, InputIterator last, F f)
{
    for (; first != last; ++first)
        boost::fusion::make_fused(f)(*first);
}

template <class InputRange, class F>
void fused_for_each(const InputRange& r, F f)
{
    fused_for_each(boost::begin(r), boost::end(r), f);
}

template <class InputRange, class F>
void fused_for_each(InputRange& r, F f)
{
    fused_for_each(boost::begin(r), boost::end(r), f);
}

} // namespace shand

#endif // SHAND_FUSED_FOR_EACH_INCLUDE


ユーザーコード

#define BOOST_RESULT_OF_USE_DECLTYPE // ラムダ式をfusedするのに必要

#include <iostream>
#include <vector>
#include <boost/fusion/include/make_vector.hpp>
#include "fused_for_each.hpp"

namespace fusion = boost::fusion;

int main()
{
    const std::vector<fusion::vector<int, char>> v = {
        fusion::make_vector(1, 'a'),
        fusion::make_vector(2, 'b'),
        fusion::make_vector(3, 'c')
    };

    shand::fused_for_each(v, [](int x, char c) {
        std::cout << x << ' ' << c << std::endl;
    });
}
1 a
2 b
3 c


ここまで書いて気づいたのですが、関数を渡す際にfusedにすれば、
アルゴリズムを再実装する必要はないですね。

#define BOOST_RESULT_OF_USE_DECLTYPE

#include <iostream>
#include <vector>
#include <boost/fusion/include/make_vector.hpp>
#include <boost/fusion/include/make_fused.hpp>
#include <boost/range/algorithm/for_each.hpp>

namespace fusion = boost::fusion;

int main()
{
    const std::vector<fusion::vector<int, char>> v = {
        fusion::make_vector(1, 'a'),
        fusion::make_vector(2, 'b'),
        fusion::make_vector(3, 'c')
    };

    boost::for_each(v, fusion::make_fused([](int x, char c) {
        std::cout << x << ' ' << c << std::endl;
    }));
}

こっちにしよう。