2014-11-23 3 views
1

Рассмотрим следующий код:повышение :: any_range и оператор []

#include <boost/range.hpp> 
#include <boost/range/any_range.hpp> 
#include <boost/range/join.hpp> 

#include <iostream> 
#include <algorithm> 
#include <string> 
#include <vector> 
#include <list> 

struct TestData { 
    TestData() : m_strMem01("test"), m_intMem02(42), m_boolMem03(true) {} 
    std::string m_strMem01; 
    int m_intMem02; 
    bool m_boolMem03; 
}; 

struct IntComp { 
    bool operator()(const TestData &s, int i) { return s.m_intMem02 < i; } 
    bool operator()(int i, const TestData &s) { return i < s.m_intMem02; } 
    bool operator()(const TestData &i, const TestData &s) { 
    return i.m_intMem02 < s.m_intMem02; 
    } 
}; 
struct StrComp { 
    bool operator()(const TestData &s, const std::string &str) { 
    return s.m_strMem01 < str; 
    } 
    bool operator()(const std::string &str, const TestData &s) { 
    return str < s.m_strMem01; 
    } 
    bool operator()(const TestData &i, const TestData &s) { 
    return i.m_strMem01 < s.m_strMem01; 
    } 
}; 

typedef boost::any_range<TestData, boost::forward_traversal_tag, 
         const TestData &, std::ptrdiff_t> TestRange; 

std::vector<TestData> vecData(10); 
std::list<TestData> listData(20); 

TestRange foo() { 
    TestRange retVal; 

    auto tmp1 = std::equal_range(vecData.cbegin(), vecData.cend(), 42, IntComp()); 
    retVal = boost::join(retVal, tmp1); 
    auto tmp2 = 
     std::equal_range(listData.cbegin(), listData.cend(), "test", StrComp()); 
    retVal = boost::join(retVal, tmp2); 
    return retVal; 
} 

int main(int argc, char *argv[]) { 
    auto res = foo(); 
    for (auto a : res) { 
    std::cout << a.m_strMem01 << std::endl; 
    } 
    //std::cout << res[4].m_intMem02 << std::endl; 
} 

Если вы раскомментировать последнюю строку код не так distance_to не реализована для any_forward_iterator_interface. Я не уверен, что именно мне здесь не хватает, например, внедрение operator[] или distance_to, но для чего? Мой собственный тег обхода версии? И почему это не работает в первую очередь?

Coliru version

ответ

2

Я бы сказал, что ответ зависит от ваших потребностей и производительности вашей лени, когда речь идет о реализации нового итератора абстракции. Основная причина, по которой ваш оператор [] не работает, заключается в том, что std :: list < ...> не предоставляет итератор обхода случайного доступа. Если бы вы выбрали контейнер, который предоставляет такой итератор. Вы any_range < ...> могли бы взять random_access_traversal_tag, и все будет хорошо. Я думаю, что справедливо сказать, что реализовать такой азарт для случайного доступа поверх списка просто не нужно, просто инкапсулируя текущий индекс и рассчитывая вперед и назад в списке всякий раз, когда требуется доступ к определенной позиции, но это явно противоречит характеру списка.

  • Есть ли веские основания удерживать одну из коллекции в списке?
  • Есть ли веские основания для доступа к полученному any_range случайным образом?
  • Стоит ли прилагать усилия для обеспечения неэффективного интерфейса произвольного доступа для std :: list?
+0

хорошо пункт. Во-первых, реализация списка объясняет, почему нет оператора []. по вашим вопросам. в реальной жизни нет списка или вектора, это был просто пример. в моем случае это Boost MIC, который фактически скрывает его реализацию, и я не могу реализовать оператор [] поверх всего. но теперь, когда я понимаю «ПОЧЕМУ», я могу смотреть дальше в MIC, может быть, я могу поиграть с индексом, чтобы обеспечить произвольный доступ. – kreuzerkrieg

+0

@kreuzerkrieg В следующий раз просто укажите, что вы ** действительно ** пытаетесь достичь в вопросе. Ускорение MIC делает его очень ясным, когда операторские скобки реализованы (а именно, для индексов 'random_access' и' unique'). Конечно, здесь вам нужен индекс 'random_access'. Если вы используете это, ваш any_range также будет иметь произвольный доступ. – sehe

+0

yup, в последнее время мои упрощенные примеры делают больше беспорядка, чем экономия от беспорядка :( – kreuzerkrieg

1

Конечно any_iterator (который лежит в основе реализации any_range) не безвозмездно копирует итераторы RandomAccess для любого нечетного итератора, который вы передаете.

Если вы этого хотите, просто сделайте адаптер итератора, который делает это (что делает его очень медленным для элементов произвольного доступа в списке - так что не делайте этого).

+0

Я не буду :) Они будут счастливо жить без него ... или нет – kreuzerkrieg