lundi 27 juin 2016

Reimplement insert iterator to make easy work with "related types" to the one stored on the container

We have the following lightweight classes:

struct A {};
struct B { A get_a() const { return /* sth */; } };

And let's suppose I have an ordered container of type A, and I want to copy objects from another container of type B to it:

std::copy(b_cont.begin(), b_cont.end(),
          std::make_insert_iterator(a_cont, a_cont.end())
         );

Of course, it won't work because a_cont and b_cont have different types, and classes A and B don't provide conversion operators. The most obvious solution is to call the function get_a for each B object on the range [b_cont.begin(), b_cont.end()), so, lets write a custom insert iterator:

template<template<class...> class container>
struct ba_insert_iterator : public std::insert_iterator<container<A> >
{
    using std::insert_iterator<container<A>>::insert_iterator;

    ba_insert_iterator& operator=(B const& o)
    {
        std::insert_iterator<container<A>>::operator=(o.get_a());

        return *this;
    }
};

template<template<class...> class container>
ba_insert_iterator<container> make_a_inserter(container<A>& c)
{ return ba_insert_iterator<container>(c, c.end()); }

Just an iterator that receives an object of type B, instead of another one of type A, and a function to create them easily. But when instantiating the template:

std::copy(b_cont.begin(), b_cont.end(), make_a_inserter(a_cont));

It says that it doesn't find the operator= because the second operand is an A object (as expected), but the first operand is an std::insert_iterator<std::set<A> >!!, so the compiler is "casting" the iterator to its clase base, which of course lacks of a method for receiving B objects to insert.

Why does it happen?

Aucun commentaire:

Enregistrer un commentaire