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

RangeEx Rangeアダプタ適用結果をMutable Algorithmに渡せない

C++

【Range】 invalid initialization of non-const type with adaptors


これがコンパイル通らない。
(一時オブジェクトを左辺値参照に束縛できてしまうVC++では言語拡張をOFFにすること)

#include <vector>
#include <boost/range/algorithm/fill.hpp>
#include <boost/range/adaptor/reversed.hpp>

int main()
{
    std::vector<int> v(10);
    boost::fill(v | boost::adaptors::reversed, 1); // エラー!
}


コンパイルが通らない理由は、boost::fillが以下のようにForwardRangeの左辺値参照を引数にとるため、Rangeアダプタの適用結果として返されるiterator rangeの一時オブジェクトを左辺値として扱えないから。

template< class ForwardRange, class Value >
inline ForwardRange& fill(ForwardRange& rng, const Value& val);


Ovenではコンパイルが通り、動作もするが、Rangeアダプタの適用結果をMutable Algorithmに渡すようなケースはあまりないかもしれない。

#include <vector>
#include <pstade/oven/algorithm.hpp>
#include <pstade/oven/reversed.hpp>

namespace oven = pstade::oven;

int main()
{
    std::vector<int> v(10);
    oven::fill(v | oven::reversed, 1); // OK
}


ちなみに、RangeExでこういったケースに対応するには、Rangeアダプタの適用結果を非constの一時変数に格納してからMutable Algorithmに渡すか、Boost.Foreachを使え、とのこと。

#include <vector>
#include <boost/typeof/typeof.hpp>
#include <boost/range/algorithm/fill.hpp>
#include <boost/range/adaptor/reversed.hpp>

int main()
{
    std::vector<int> v(10);

    BOOST_AUTO(r, (v | boost::adaptors::reversed));
    boost::fill(r, 1); // OK
}
#include <vector>
#include <boost/foreach.hpp>
#include <boost/range/adaptor/reversed.hpp>

int main()
{
    std::vector<int> v(10);

    BOOST_FOREACH (int& x, v | boost::adaptors::reversed) {
        x = 1; // OK
    }
}