Rokiのチラ裏

学生による学習のログ

パイプライン記法での連続的な挿入操作

は必要あるだろうか。

boost.assignではoperator+=を使って連続的な挿入を実現しているがパイプライン記法に入れる事は出来ない。

template<class F,class Range>
auto operator|(const Range& r,const F& f)
{
    return f(r);
}

template<class Iterator>
struct copied_t_impl{
    explicit copied_t_impl(Iterator first,Iterator last):first_(first),last_(last){}
    template<class T>
    operator T()const{return T(first_,last_);}
private:
    Iterator first_,last_;
};
template<class Iterator>
copied_t_impl<Iterator> make_copied_t_impl(Iterator first,Iterator last){return copied_t_impl<Iterator>(first,last);}
struct copied_t{
    template<class Range>
    auto operator()(const Range& r)const{return make_copied_t_impl(r.begin(),r.end());}
}copied={};


using namespace boost::assign;
std::vector<int> v;
std::vector<int> result = v+=1,2,3,4,5 | boost::adaptors::reversed | copied; // 当然ムリ

そこでパイプラインで使えるようfold expressionでも使ってパッと実装した。パッと書けるものだが、毎度二度手間になると面倒なので書いておく事にした。

template<class Pred,class Range,class Tuple,std::size_t... I>
auto apply_(Pred pred,Range& r,Tuple& tpl,std::index_sequence<I...>)
{
    return pred(r,std::get<I>(tpl)...);
}

template<class Pred,class Range,class... Args,
    class Indices=std::make_index_sequence<std::tuple_size<std::tuple<Args...>>::value>>
auto apply(Pred pred,Range& r,std::tuple<Args...>& tpl)
{
    return apply_(pred,r,tpl,Indices());
}

template<class Range,class Function>
auto operator|(Range& r,Function f){return f(r);}
template<class Range,class Function>
auto operator|(const Range& r,Function f){return f(r);}

template<class Predicate,class... Args>
struct variadicer_t{
    explicit variadicer_t(Predicate pred,Args... args)
        :pred_(pred),args_(args...){}
    template<class Range>
    auto operator()(Range& r){return apply(pred_,r,args_);}
private:
    Predicate pred_;
    std::tuple<Args...> args_;
};

template<class Predicate,class... Args>
variadicer_t<Predicate,Args...> variadic(Predicate pred,Args&&... args)
{
    return variadicer_t<Predicate,Args...>(pred,std::forward<Args>(args)...);
}

const struct emplacer_t{
    template<class Range,class... Args>
    Range& operator()(Range& r,Args&&... args)
    {
        (r.emplace_back(std::forward<Args>(args)),...);
        return r;
    }
}emplacer={};

const struct emplace_fronter_t{
    template<class Range,class... Args>
    Range& operator()(Range& r,Args&&... args)
    {
        (r.emplace_front(std::forward<Args>(args)),...);
        return r;
    }
}emplace_fronter={};

以下のように使える。

struct OnlyHeadAndTail_Iterator_Tag{};
template<class Iterator>
using derived_type=std::iterator<OnlyHeadAndTail_Iterator_Tag,typename std::iterator_traits<Iterator>::value_type>;
template<class Iterator>
struct range_iterator:public derived_type<Iterator>{
    typedef Iterator iterator;
    typedef iterator const_iterator;
    
    explicit range_iterator(Iterator first,Iterator last):first_(first),last_(last){}
    iterator begin()const{return first_;}
    iterator end()const{return last_;}
    const_iterator cbegin()const{return first_;}
    const_iterator cend()const{return last_;}
private:
    iterator first_,last_;
};
template<class Iterator>
range_iterator<Iterator> make_range_iterator(Iterator first,Iterator last){return range_iterator<Iterator>(first,last);}

template<class Iterator>
struct copied_t_impl{
    explicit copied_t_impl(Iterator first,Iterator last):first_(first),last_(last){}
    template<class Range>
    operator Range()const{return Range(first_,last_);}
private:
    Iterator first_,last_;
};
template<class Iterator>
copied_t_impl<Iterator> make_copied_t_impl(Iterator first,Iterator last){return copied_t_impl<Iterator>(first,last);}
const struct copied_t{
    template<class Range>
    auto operator()(const Range& r)const{return make_copied_t_impl(r.begin(),r.end());}
}copied={};

const struct print_t{
    template<class Range>
    const Range& operator()(const Range& r)const
    {
        boost::copy(r,std::ostream_iterator<typename Range::value_type>(std::cout," "));
        std::cout<<std::endl;
        return r;
    }
}print={};

int main()
{
    std::vector<int> v = boost::irange(0,5) | copied;
    std::vector<int> result = v | 
        variadic(emplacer,6,7,8,9,10,11,12) | 
        boost::adaptors::reversed | 
        boost::adaptors::filtered([](const auto& x){return x%2==0;}) |
        boost::adaptors::transformed([](const auto& x){return x*x;}) |
        print | // 144 100 64 36 16 4 0
        copied;

    std::list<int> li = boost::irange(0,5) | copied;
    li | variadic(emplace_fronter,1,2,3,4,5,6) | print; // 6 5 4 3 2 1 0 1 2 3 4
}

一応ライブラリ化した。