2011-07-04 21 views
7

Me encontré con un extraño problema de compilación. Quiero procesar una lista de cadenas, usando std::for_each. El siguiente código simplificado ilustra el problema:std :: for_each ignorando la función predeterminada argumento

# include <list> 
# include <string> 
# include <algorithm> 

using namespace std ; 

void f(wstring & str) 
{ 
    // process str here 
} 

void g(wstring & str, int dummy = 0) 
{ 
    // process str here, same as f, just added a second default dummy argument 
} 

int main(int, char*[]) 
{ 
    list<wstring> text ; 

    text.push_back(L"foo") ; 
    text.push_back(L"bar") ; 

    for_each(text.begin(), text.end(), f) ; // OK, fine :) 
    for_each(text.begin(), text.end(), g) ; // Compilation error, complains about 
        // g taking 2 arguments, but called within std::for_each 
        // with only one argument. 

    // ... 
    return 0 ; 
}  

Probé utilizando MinGW 4.5.2 y MSVC10, tanto informó el mismo mensaje de error. Originalmente, quería usar boost::algorithm::trim como una función de procesamiento pasada a std::for_each, pero encontré que toma dos argumentos, el primero es obligatorio (la cadena para procesar) y el segundo es opcional (una configuración regional que proporciona una definición de caracteres espaciales) .

¿Hay alguna manera de mantener las cosas limpias cuando se usa std::for_each (y otros algoritmos estándar) cuando se tienen funciones o métodos con argumentos predeterminados? He encontrado una manera de hacer que funcione, pero no es más clara y fácilmente comprensible, por lo que un bucle for empieza a parecer más fácil ...

# include <list>  
# include <string> 
# include <algorithm> 
# include <boost/bind.hpp> 
# include <boost/algorithm/string.hpp> 

using namespace std ; 
using namespace boost ; 

// ... somewhere inside main 
list<wstring> text ; 
for_each(text.begin(), text.end(), bind(algorithm::trim<wstring>, _1, locale()) ; 
// One must deal with default arguments ... 
// for_each(text.begin(), text.end(), algorithm::trim<wstring>) would be a real pleasure 

Gracias por cualquier ayuda!

Nota: acabo de comenzar el aprendizaje de Inglés, lo siento por los errores :)

+0

Creo que simplemente no funciona de esta manera para los funtores. Eliminar el argumento ficticio. –

+0

El argumento ficticio que agregué a 'g' fue para demostrar el comportamiento extraño de' std :: for_each'. Llamar a 'g' con algunos' wstring str' como 'g (str)' funciona como un amuleto, pero no dentro de 'std :: for_each'. En mi caso, usar 'boost :: algorithm :: trim' directamente como un functor es imposible sin trucos, debido a que su segundo argumento es opcional (std :: locale) – overcoder

+2

@Overcoder: eso es porque' g ​​(str) 'de inmediato se convierte en 'g (str, 0)' - el argumento predeterminado es solo azúcar de generación de código. –

Respuesta

6

argumentos por defecto son sólo una herramienta de generación de código y no forma parte de la firma de la función, por lo que realmente no se puede conseguir alrededor de eso. Puede ajustar su función en un objeto de función, pero eso es precisamente lo que bind ya hace por usted.

Sin embargo, en C++ 0x que convenientemente se puede almacenar el resultado (y utilizar std::bind) que tal vez hacer el código un poco más legible:

auto trimmer = std::bind(boost::algorithm::trim<std::wstring>, std::placeholders::_1, std::locale()); 

std::for_each(text.begin(), text.end(), trimmer); 

(La razón por la que no quiere hacer eso en C++ 98/03 es que el tipo de devolución de bind es algo antiestético, y no le harías ningún favor a alguien al deletrearlo.)

Alternativamente, otra vez en C++ 0x, podrías utilice una lambda:

std::for_each(text.begin(), text.end(), [](std::wstring & s){ boost::algorithm::trim<std::wstring>(s); }); 
+2

Además, si te quedas con el estándar actual, echa un vistazo a bind2nd (de hecho, tiene algunos requisitos para functors - tu g debe ser struct inherited from binary_function) – cybevnm

+0

@vnm: sí, buen punto, una dependencia menos boost: ' std :: for_each (..., ..., std :: bind2nd (boost :: algorithm :: trim , std :: locale())); '. –

+1

¡Gracias! Veré si puedo habilitar C++ 0x para mi proyecto actual. Lambdas parece más conveniente. – overcoder

Cuestiones relacionadas