2014-11-09 2 views
0

Мой вопрос включает в себя повторное использование кода для алгоритма const unaware (может использоваться с постоянными или изменяемыми объектами)?Константа против взаимозаменяемых итераторов: один и тот же алгоритм разного кода

Возьмем, к примеру, итераторы std::vector.
Существует два класса итераторов, которые имеют сходные методы: std::vector::iterator и std::vector::const_iterator.

Оба итератора указывают на слоты в векторе или за пределами этого вектора (например, std::vector::end()).
Оба они имеют методы приращения и уменьшения. Основное отличие состоит в том, что const_iterator не может использоваться для записи в вектор.

Если бы я писал код для итераторов, как я мог использовать методы общего доступа iterator и const_iterator, которые не зависят от константы операции доступа?

В моем настоящем кодексе я дублирую код для for_each и visit методов из-за разницы в доступности. Цикл for_each совпадает с циклом for, за исключением того, что применяется один параметр const_visitor, а другой применяется mutable_visitor.

struct Object; 

struct Const_Visitor 
{ 
    // Visit function cannot modified the given object. 
    virtual void visit(const Object& o) = 0; 
}; 

struct Mutable_Visitor 
{ 
    // The visit function may modify the given object; 
    virtual void visit(Object& o) = 0; 
}; 

struct Container 
{ 
    const unsigned int LIMIT = 16; 
    Object obj_container[LIMIT]; 

    // Apply the read-only (constant) visitor 
    // to each object in the container 
    void for_each(Const_Visitor& cv) const 
    { 
    // Note: this loop management is the same 
    // as the loop management for the mutable for_each() method. 
    for (unsigned int i = 0; i < LIMIT; ++i) 
    { 
     cv.visit(obj_container[i]); 
    } 
    } 


    // Apply the read/write (mutable) visitor 
    // to each object in the container. 
    void for_each(Mutable_Visitor& mv) 
    { 
    // Note: this loop management is the same 
    // as the loop management for the const for_each() method. 
    for (unsigned int i = 0; i < LIMIT; ++i) 
    { 
     mv.visit(obj_container[i]); 
    } 
    } 
}; 

В приведенном выше примере, механики одинаковы для обоих for_each функций. Изменяется только посетитель. Те же самые слоты в массиве передаются в функции visit.

Это может быть немного изменено с помощью одного посетителя с двумя методами visit, но основной вопрос все еще существует.

struct Object; 

struct Single_Visitor 
{ 
    // Method can't modify the object. 
    virtual void visit(const Object& o) = 0; 

    // Method may modify the object. 
    virtual void visit(Object& o) = 0; 
}; 

struct Container 
{ 
    const unsigned int LIMIT = 16; 
    Object obj_container[LIMIT]; 

    // Apply a visitor to each item in container. 
    void for_each(Single_Visitor& sv) const 
    { 
    for (unsigned int i; i < LIMIT; ++i) 
    { 
     // Should call the visit method, 
     // constant object. 
     sv.visit(obj_container[i]); 
    } 
    } 


    // Apply a visitor to each item in container. 
    void for_each(Single_Visitor& sv) 
    { 
    for (unsigned int i; i < LIMIT; ++i) 
    { 
     // Should call the visit method, 
     // mutable object. 
     sv.visit(obj_container[i]); 
    } 
    } 
}; 

С классом для посетителей, который имеет два метода (по сравнению с двумя отдельных классов), for_each методы в контейнере по-прежнему имеет ту же механику. Цикл один и тот же, только другой метод называется.

Итак, есть ли способ иметь один цикл for_each, который вызывает соответствующую базу посетителей на const-ness?

+0

* «Основное отличие заключается в том, что' const_iterator' не может быть использованы для записи на вектор.»* Я не уверен, если это уместно, но я думаю, что правильное описание является то, что их тип значения Уста-квалифицированы. У них могут быть изменчивые члены и т. Д. – dyp

+2

Соответствует ли это решение шаблону? http://coliru.stacked-crooked.com/a/e81a4a86c4bf0453 – zch

+0

Я думаю, что проблема является одной из проблем с посетителями, упомянутыми здесь: [cppcon 2014: не принимать посетителей] (https://www.youtube.com/watch ? v = QhJguzpZOrk). Однако основная проблема может быть не связана с итераторами и посетителями; речь идет о необходимости писать дубликат кода для функций-членов из-за константы (и класса значений) экземпляра класса. – dyp

ответ

1

Невозможно иметь одну нестационарную функцию-член, которая может работать как const или не const. Вместо этого вы можете использовать шаблон non-member или static function с контейнером, переданным в качестве аргумента.

struct Container 
{ 
    Object obj_container[LIMIT]; 

    // C can match either `const Container` or `Container` 
    // V can match either `Const_Visitor` or `Mutable_Visitor` 
    template<class C, class V> 
    static void for_each(C& c, V& v) { 
    for (unsigned int i = 0; i < LIMIT; ++i) 
    { 
     v.visit(c.obj_container[i]); 
    } 
    } 

    void for_each(Const_Visitor& cv) const 
    { 
    for_each(*this, cv); 
    } 

    void for_each(Mutable_Visitor& mv) 
    { 
    for_each(*this, mv); 
    } 
}; 
+0

Если вы определяете его как функцию друга, его можно даже легко вызвать извне (если вам не нравятся функции-члены;) - хотя для этого требуются трюки ADL, если как функция-член, так и не-член должны иметь одинаковые имя. – dyp