I stumbled on a strange compilation problem. I want to process a list of strings, using std::for_each
. The following simplified code illustrates the problem :
# 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 ;
}
I tested using MinGW 4.5.2 and MSVC10, both reported the same error message. Originally, I wanted to use boost::algorithm::trim
as a processing function passed to std::for_each
, but I found that it takes two arguments, the first being mandatory (the string to process) and the second one is optional (a locale providing a definition for space chars).
Is there any way to keep things clean when using std::for_each
(and other standard algorithms) when having functions or methods with default arguments ? I found a way to make it work, but it is no more clear and easily understandable, so a for
loop begins to seem easier ...
# 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
Thanks for any help !
Note : I just started learning English, sorry for mistakes :)
Default arguments are just a code-generation tool and not part of the function signature, so you can't really get around that. You could wrap your function in a function object, but that's precisely what bind
already does for you.
However, in C++0x you can conveniently store the result (and use std::bind
) to maybe make the code a bit more readable:
auto trimmer = std::bind(boost::algorithm::trim<std::wstring>, std::placeholders::_1, std::locale());
std::for_each(text.begin(), text.end(), trimmer);
(The reason you don't want to do that in C++98/03 is that the return type of bind
is something rather unsightly, and you wouldn't be doing anyone a favour by spelling it out.)
Alternatively, again in C++0x, you could use a lambda:
std::for_each(text.begin(), text.end(), [](std::wstring & s){ boost::algorithm::trim<std::wstring>(s); });
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With