2010-01-20 8 views
8

http://www.cplusplus.com/reference/algorithm/for_each/
Función unaria tomando un elemento en el rango como argumento. Esto puede ser un puntero a una función o un objeto cuya clase sobrecarga el operador (). Se ignora su valor de retorno, si lo hay, .¿Por qué no se puede modificar su parámetro functor por cada vez?

De acuerdo con este artículo, esperaba que for_each modifica realmente el objeto dado como su tercer argumento, pero parece que for_each opera en un objeto temporal, y ni siquiera modificar el objeto dado a ella.

Entonces, ¿por qué se implementa de esa manera? Parece mucho menos útil. ¿O no entendí bien algo y mi código a continuación contiene errores?

#include <iostream> 
#include <vector> 
#include <algorithm> 

template <class T> struct Multiplicator{ 
    T mresult; 
    public: 
    const T& result() const{return mresult;} 
    Multiplicator(T init_result = 1){ 
     mresult = init_result; 
    } 
    void operator()(T element){ 
     mresult *= element; 
     std::cout << element << " "; // debug print 
    } 
}; 

int main() 
{ 
    std::vector<double> vec; 
    vec.push_back(1); 
    vec.push_back(2); 
    vec.push_back(3); 
    Multiplicator<double> multiply; 
    std::for_each(vec.begin(),vec.end(),multiply); 
    std::cout << "\nResult: " << multiply.result() << std::endl; 
    return 0; 
} 

Resultados previstos:

1 2 3 Result: 6 

pero no obtuvo resultado siguiente:

1 2 3 Result: 1 
+0

¿Qué le parece cambiar el título de su pregunta? Podría facilitar que otros lo encuentren. – BeeBand

Respuesta

15

El objeto de la función se toma por valor. for_each devuelve el objeto función, por lo que si lo cambia a:

multiply = std::for_each(vec.begin(),vec.end(),multiply); 

que obtener la salida esperada.

+1

Generalmente para los funtores, y debido a que se supone que son livianos y se pueden copiar, hago trampa y uso un atributo que hace referencia a una variable pasada al constructor. Por lo tanto, cualquier copia es estrictamente equivalente y se refiere al mismo elemento. Por supuesto, hace que la inicialización sea un poco incómoda (declarar una variable, pasarla a un funtor, leer de la variable), pero funciona bien y no requiere ninguna propiedad particular de implementación (como no descartar el último modificador). –

+0

Déjame darte la primera insignia dorada de STL –

+0

@Johannes: Gracias, pero tengo que responder a otras 36 preguntas etiquetadas [stl] primero :-) (el requisito ahora es de al menos 1,000 votos ascendentes y al menos 200 respuestas; recuerdo cuando lo cambiaron hace un año y perdí mi insignia de oro [c] durante un par de meses.) –

10

Mientras que James es correcta, usando std::accumulate con std::multiplies sería más correcto, probablemente:

#include <iostream> 
#include <functional> 
#include <numeric> 
#include <vector> 

int main(void) 
{ 
    std::vector<double> vec; 
    vec.push_back(1); 
    vec.push_back(2); 
    vec.push_back(3); 

    double result = std::accumulate(vec.begin(), vec.end(), 
            1.0, std::multiplies<double>()); 

    std::cout << "\nResult: " << result << std::endl; 

} 

con tu versión for_each, que realmente no necesita copiar el funtor de nuevo, en lugar:

double result = std::for_each(vec.begin(), vec.end(), multiply).result(); 

o C++ 0x, para la diversión:

double result = 1; 
std::for_each(vec.begin(), vec.end(), [&](double pX){ result *= pX; }); 
+0

¿Qué es esto? "¿Sugerir la herramienta correcta para el día del trabajo?" :-) +1 –

+0

Gracias por la sugerencia. – smerlin

+0

@James: 8) Lamentablemente, la calidad de mis respuestas disminuye exponencialmente a medida que el día continúa. :pag – GManNickG

0

La semántica de For_each no encaja en lo que estás tratando de hacer. acumular hace exactamente lo que está intentando, use eso en su lugar.

Cuestiones relacionadas