2016-11-29 1 views
3

Я пытаюсь написать адаптер итератора, который должен вызывать функцию-член (или доступ к члену объекта) каждый раз, когда он разыменован. Вот пример такого API:Адаптер Iterator, который вызывает функцию-член при разыменовании

vector<pair<int,int>> ps = {{1,"a"}, {2,"b"}, {3,"c"}}; 

// Pairs that represent ranges 
auto rf = make_adaptor(ps.begin(), ps.end(), [](const auto& x) {return x.first;} 
auto rs = make_adaptor(ps.begin(), ps.end(), [](auto& x) {return x.second;} 

Если распечатать 123:

for_each(rf.first, rf.second, [](const auto& x){std::cout << x;}); 

Если установить каждый second элемент пары в ps:

for_each(rs.first, rs.second, [](auto& x){ x = "hello";}); 

Я пытался писать собственный тип iterator вместе с методом make_adaptor, но я не могу заставить его работать:

template <typename Iterator, typename UnaryOp> 
struct adaptor { 
    using value_type = std::result_of<UnaryOp(typename Iterator::reference)>::type; 
    using reference = value_type&; 
    using pointer = value_type*; 
    using difference_type = typename Iterator::difference_type; 
    using iterator_category = typename Iterator::iterator_category; 

    adaptor(){}; 
    adaptor(Iterator it, UnaryOp func) : _it(it), _func(func) {} 

    reference operator*() const { return _func(*_it); } 
    pointer operator->() const { return &_func(*_it); } 

    bool operator==(const adaptor& other) const { return _it == other._it; } 
    bool operator!=(const adaptor& other) const { return _it != other._it; } 

    adaptor& operator++() { 
     ++_it; 
     return *this; 
    } 

    Iterator _it; 
    UnaryOp _func; 
}; 



template <typename Iterator, typename UnaryOp> 
    auto make_adaptor(Iterator first, Iterator last, UnaryOp func) { 
     return std::make_pair(adaptor<Iterator, UnaryOp>(first, func), 
           adaptor<Iterator, UnaryOp>(last, func)); 
    }; 

Причина этого заключается в следующем: Допустим, у меня есть алгоритм convex_hull, который работает на points. Но теперь у меня есть объекты, которые содержат points в качестве участника (struct A { points pos;};). Я хочу позвонить convex_hull в коллекцию A s.

+1

Примечание: 'operator->' возвращает адрес из временного, а также '' оператор * возвращает оборванных ссылку. – Zereges

+0

Это одна из проблем, с которыми я столкнулся, к сожалению, я не знаю, как их решить в общем виде. – fuji

+0

Я бы определенно кэшировал результат вызова функции, поскольку вы, вероятно, не хотите вычислять 'func' каждый раз, когда итератор получает разыменованные. Затем вы можете вернуть переменную cahced (или ее адрес) и комментарий, что * приращение адаптера приведет к ее недействительности. * – Zereges

ответ

0

С range-v3, вы можете сделать что-то похожее на:

const std::vector<std::pair<int,const char*>> ps = {{1,"a"}, {2,"b"}, {3,"c"}}; 

for (const auto s : ps | ranges::view::keys) 
{ 
    std::cout << " " << s; 
} 

for (const auto s : ps | ranges::view::transform([](const auto& p) { return p.first;})) 
{ 
    std::cout << " " << s; 
} 

Demo

Смежные вопросы