La concatenación de iterador C ++ oscila en una variable miembro vector const en el tiempo de construcción

StackOverflow https://stackoverflow.com/questions/757153

Pregunta

Tengo una X clase, que proporciono un fragmento de aquí:

class X {
  public:
    template <typename Iter>
    X(Iter begin, Iter end) : mVec(begin, end) {}

  private:
    vector<Y> const mVec;
};

Ahora quiero añadir un nuevo constructor de la concatenación de esta clase, algo como:

template <typename Iter1, typename Iter2>
X(Iter1 begin1, Iter1 end1, Iter2 begin2, Iter2 end2) : mVec(???) { ??? }

Tal constructor sería concatenar los dos rangos [begin1, END1) y [begin2, end2) en MVEC. Los desafíos son

1) Me gustaría recibir para preservar la const en MVEC, de modo que se considera constante a través de los otros métodos de X.

2) Me gustaría evitar copias innecesarias si es posible. Es decir, una solución es tener un método estático que construye un no constante temporal para variar 1, insertos oscilan 2 y lo devuelve, y luego definir el constructor concatenando a

template <typename Iter1, typename Iter2>
X(Iter1 begin1, Iter1 end1, Iter2 begin2, Iter2 end2) 
  : mVec(concatenate(begin1, end1, begin2, end2)) { }

pero que copia todos los valores al menos una vez más, creo.

¿Fue útil?

Solución

Niza problema. Me gustaría tratar de implementar un tipo envoltura iterador particular que convierte los dos rangos en un único rango. Algo en la línea de:

// compacted syntax for brevity...
template <typename T1, typename T2>
struct concat_iterator
{
public:
   typedef std::forward_iterator_tag iterator_category;
   typedef typename iterator_traits<T1>::value_type value_type;
   typedef *value_type pointer; 
   typedef &value_type reference;

   concat_iterator( T1 b1, T1 e1, T2 b2, T2 e2 ) 
      : seq1( b1 ), seq1end( e1 ), seq2( b2 ), seq2end( e2 );
   iterator& operator++() {
      if ( seq1 != seq1end ) ++seq1;
      else ++seq2;
      return this;
   }
   reference operator*() {
      if ( seq1 != seq1end ) return *seq1;
      else return *seq2;
   }
   pointer operator->() {
      if ( seq1 != seq1end ) return &(*seq1);
      else return &(*seq2);
   }
   bool operator==( concat_iterator const & rhs ) {
      return seq1==rhs.seq1 && seq1end==rhs.seq2 
          && seq2==rhs.seq2 && seq2end==rhs.seq2end;
   }
   bool operator!=( contact_iterator const & rhs ) {
      return !(*this == rhs);
   }
private:
   T1 seq1;
   T1 seq1end;
   T2 seq2;
   T2 seq2end;
};

template <typename T1, typename T2>
concat_iterator<T1,T2> concat_begin( T1 b1, T1 e1, T2 b2, T2 e2 )
{
   return concat_iterator<T1,T2>(b1,e1,b2,e2);
}
template <typename T1, typename T2>
concat_iterator<T1,T2> concat_end( T1 b1, T1 e1, T2 b2, T2 e2 )
{
   return concat_iterator<T1,T2>(e1,e1,e2,e2);
}

Ahora puede usar:

 class X {
 public:
    template <typename Iter, typename Iter2>
    X(Iter b1, Iter e1, Iter2 b2, Iter2 e2 ) 
      : mVec( concat_begin(b1,e1,b2,e2), concat_end(b1,e1,b2,e2) ) 
    {}

  private:
    vector<Y> const mVec;
};

o (simplemente he pensado en ella) que no es necesario redeclare su constructor. Asegúrese de que su interlocutor utilizar las funciones de ayuda:

X x( concat_begin(b1,e1,b2,e2), concat_end(b1,e1,b2,e2) );

No he comprobado el código, acaba de escribir aquí la parte superior de mi cabeza. Podría compilar o no podría, podría funcionar o no ... pero se puede tomar esto como un punto de inicio.

Otros consejos

Probablemente sería mejor para caer const (¿por qué insistir en que de todos modos?).

De lo contrario, usted tiene que construir un iterador de concatenación. Es un buen montón de código, consulte este tema por más.

Una de las mejores o peores características de C ++, dependiendo de su punto de vista, es que se puede abusar de ella cuando sea necesario para hacer el trabajo. En este caso, la víctima es const_cast:

template <typename Iter1, typename Iter2>
X(Iter1 begin1, Iter1 end1, Iter2 begin2, Iter2 end2) : mVec(begin1, end1) {
    const_cast<vector<Y>&>(mVec).insert(mVec.end(), begin2, end2);
}

Puede que tenga algunos de los detalles equivocado, yo no intento compilar esto. Pero hay que darle la idea.

Su método estático no puede ser tan malo como usted piensa, en función de la optimización de su compilador hace. Y en C ++ 0x, mover constructores eliminará cualquier copia que está teniendo lugar actualmente.

Mientras tanto ir con un iterador envoltura. El código no es probable que sea tan malo como los enlaces a avakar hilo, ya que sólo hay que implementar un entrada iterador .

  

1) Me gustaría recibir para preservar la const en MVEC, de modo que se considera constante a través de los otros métodos de X.

  • Este es un uso curioso de const en una variable miembro. Y desafía buen diseño. Por definición, la construcción es un proceso que requiere el objeto a cambiar.

  • En cuanto a su requerimiento para mantener el objeto no modificable - utilizar la encapsulación adecuada. Debe utilizar funciones const miembros para exponer cualquier funcionalidad basada en su mVec para los clientes de su clase.

2) Me gustaría evitar copias innecesarias si es posible. Es decir, una solución es tener un método estático que construye un no constante temporal para variar 1, insertos oscilan 2 y lo devuelve, y luego definir el constructor concatenando a

Se debe buscar en movimiento-constructores y referencias de valor R en general (una meta prometida de C ++ 0x). Lea este artículo .

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top