Estoy tratando de entender cómo funciona la función std :: transform, pero tengo algunos problemas con el siguiente código. Quiero tomar un multiset ms, agregar 1 al contenido de cada elemento y almacenarlos en un nuevo multiset msc. Esto es lo que tengo:

int op_increase(int i) { return ++i; }

int main()
{

std::multiset<int> ms = {1,1,2,2,3};
std::multiset<int> msc;
std::transform(ms.begin(), ms.end(), msc.begin(), op_increase);

return 0;
}

Sin embargo me sale el siguiente error:

C3892: _Dest: no se puede asignar a una variable que sea constante

1
lebman 31 jul. 2016 a las 09:30

2 respuestas

La mejor respuesta

Su código no estaba utilizando el argumento correcto para std::transform que permite la inserción en un contenedor vacío. Esto requiere el uso de un iterador que sea lo suficientemente inteligente como para llamar a la función apropiada que llama a la función insert() del contenedor.

La solución es proporcionar std::transform el std::inserter iterador que se inserta automáticamente en el multiset vacío. Aquí hay un ejemplo:

#include <set>
#include <algorithm>
#include <iterator>

int op_increase(int i) { return ++i; }

int main()
{
    std::multiset<int> ms = {1,1,2,2,3};
    std::multiset<int> msc;
    std::transform(ms.begin(), ms.end(), std::inserter(msc, msc.begin()), op_increase);
    // msc now contains 2,2,3,3,4  
}

Tenga en cuenta que se usa std::inserter, y no simplemente msc.begin(). El insertador insertará automáticamente los elementos en el mapa.

Ejemplo en vivo

3
PaulMcKenzie 31 jul. 2016 a las 11:35

El problema aquí es que std::multiset<T>::begin() devuelve un tipo std::_Tree_const_iterator. Por eso no puede cambiar su valor. Este comportamiento es sensato: el std::multiset, como std::set, es un contenedor ordenado implementado típicamente como un árbol rojo-negro y, por lo tanto, el cambio de un valor de un elemento puede requerir la actualización de toda la estructura de datos. Si el usuario realmente quiere hacer esto, puede borrar un nodo y volver a agregarlo.

Para comprender mejor el comportamiento de std::transform, puede usar el contenedor std::vector en lugar de std::multiset. Cplusplus.com contiene un buen ejemplo de código que utiliza std::transform.

Además, por lo que entiendo por su código, intenta agregar los datos resultantes en el std::multiset inicialmente vacío. Para lograr esta funcionalidad, puede utilizar std::insert_iterator (Cplusplus.com) , como esto:

int op_increase(int i) { return ++i; }

int main()
{
    std::multiset<int> ms = {1,1,2,2,3};
    std::multiset<int> msc;
    std::transform(ms.begin(), ms.end(), inserter(msc, msc.begin()), op_increase);
    return 0;
}
2
alexeykuzmin0 31 jul. 2016 a las 06:49