Brian Bi
Brian Bi

Reputation: 119552

Why does this code involving boost::transform_iterator with a non-movable type not work?

This code was inspired by another question on Stack Overflow a few days ago. It attempts to use a transform iterator to construct a std::vector containing a non-movable type.

#include <cstdio>
#include <iterator>
#include <vector>

#define BOOST_RESULT_OF_USE_DECLTYPE
#include <boost/iterator/transform_iterator.hpp>

struct NonMovable {
    NonMovable(const NonMovable&) = delete;
    void operator=(const NonMovable&) = delete;
    NonMovable(NonMovable&&) = delete;  // redundant
    void operator=(NonMovable&&) = delete;  // redundant
    NonMovable(int x, int y) : x(x), y(y) {}
    int x;
    int y;
};

int main(int argc, char* argv[])
{
    std::vector<int> args = {1, 2, 3, 4};
    int additional_arg = 5;
    auto fun = [&additional_arg](auto arg) { return NonMovable(arg, additional_arg); };
    std::vector<NonMovable> v(boost::make_transform_iterator(args.begin(), fun),
                              boost::make_transform_iterator(args.end(), fun));
    for (const auto& item : v) {
        printf("%d %d\n", item.x, item.y);
    }
}

Unfortunately, this code doesn't compile (https://wandbox.org/permlink/20xMUsCBUg44YmXC). The error message from Clang mentions that the std::vector range constructor is disabled because:

no type named 'reference' in 'std::__1::iterator_traits<boost::iterators::transform_iterator<(lambda at prog.cc:22:16), std::__1::__wrap_iter<int *>, boost::iterators::use_default, boost::iterators::use_default> >'

But I can't see any reason why this iterator_traits specialization should not have a member named reference.

Upvotes: 2

Views: 127

Answers (0)

Related Questions