2011-07-04 27 views
7

Я наткнулся на странную проблему компиляции. Я хочу обработать список строк, используя std::for_each. Следующий упрощенный код иллюстрирует проблему:std :: for_each игнорирование аргумента функции по умолчанию

# 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 ; 
}  

я тестировал с использованием MinGW 4.5.2 и MSVC10, как сообщается то же сообщение об ошибке. Первоначально я хотел использовать boost::algorithm::trim как функцию обработки, переданную в std::for_each, но я обнаружил, что он принимает два аргумента, первый из которых является обязательным (строка для обработки), а вторая необязательна (локаль, предоставляющая определение для пробелов) ,

Есть ли способ сохранить чистоту при использовании std::for_each (и других стандартных алгоритмов) при наличии функций или методов с аргументами по умолчанию? Я нашел способ, чтобы заставить его работать, но это не более ясно и легко понять, так что for петля начинает казаться проще ...

# 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 

Спасибо за любую помощь!

Примечание: Я только начал изучать английский язык, извините за ошибки :)

+0

Я думаю, что это просто не работает для функторов. Удалите фиктивный аргумент. –

+0

Фиктивный аргумент, который я добавил в 'g', должен был продемонстрировать странное поведение' std :: for_each'. Вызов 'g' с некоторой' wstring str' как 'g (str)' работает как шарм, но не внутри 'std :: for_each'. В моем случае использование 'boost :: algorithm :: trim' непосредственно в качестве функтора невозможно без трюков, поскольку его второй аргумент является необязательным (std :: locale) – overcoder

+2

@Overcoder: это потому, что' g (str) 'немедленно становится 'g (str, 0)' - аргумент по умолчанию - это просто код, генерирующий сахар. –

ответ

6

аргументов по умолчанию является лишь инструментом генерации коды и не является частью сигнатуры функции, так что вы не можете обойти это. Вы можете обернуть свою функцию в объект функции, но это именно то, что уже делает для вас bind.

Однако в C++ 0x можно удобно хранить результат (и использовать std::bind), чтобы, возможно, сделать код немного более читаемым:

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

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

(Причина вы не хотите, чтобы сделать это в C++ 98/03 это то, что возвращаемый тип bind - это что-то довольно неприглядное, и вы не будете никому одолжить, написав его.)

В качестве альтернативы, снова в C++ 0x, вы можете используйте лямбда:

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

Кроме того, если вы застряли с текущим стандартом, посмотрите на bind2nd (действительно, у него есть некоторые требования для функторов - ваш g должен быть унаследован от функции binary_function) – cybevnm

+0

@vnm: да, хорошая точка, одна меньшая зависимость от перенапряжения: ' std :: for_each (..., ..., std :: bind2nd (boost :: algorithm :: trim , std :: locale())); '. –

+1

Спасибо! Я посмотрю, могу ли я включить C++ 0x для моего текущего проекта. Лямбдас кажется более удобным. – overcoder

Смежные вопросы