2011-07-04 3 views
7

Je suis tombé sur un étrange problème de compilation. Je veux traiter une liste de chaînes, en utilisant std::for_each. Le code simplifié suivant illustre le problème:std :: for_each ignorer l'argument de la fonction par défaut

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

Je l'ai testé en utilisant MinGW 4.5.2 et MSVC10, tous deux ont signalé le même message d'erreur. A l'origine, je voulais utiliser boost::algorithm::trim comme une fonction de traitement passée à std::for_each, mais j'ai trouvé qu'il fallait deux arguments, le premier étant obligatoire (la chaîne à traiter) et le second optionnel (un paramètre régional fournissant une définition pour les caractères d'espace) .

Y a-t-il un moyen de garder les choses propres lorsque vous utilisez std::for_each (et d'autres algorithmes standard) lorsque vous avez des fonctions ou des méthodes avec des arguments par défaut? J'ai trouvé un moyen de le faire fonctionner, mais il est plus claire et facilement compréhensible, donc une boucle for commence à sembler plus facile ...

# 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 

Merci pour toute aide!

Remarque: Je viens de commencer à apprendre l'anglais, désolé pour les erreurs :)

+0

Je pense que ça ne fonctionne tout simplement pas ainsi pour les foncteurs. Supprimez l'argument fictif. –

+0

L'argument fictif que j'ai ajouté à 'g' était de démontrer le comportement étrange de' std :: for_each'. Appeler 'g' avec un' wstring str' comme 'g (str)' fonctionne comme un charme, mais pas dans 'std :: for_each'. Dans mon cas, utiliser boost :: algorithm :: trim' directement en tant que foncteur est impossible sans astuces, car son second argument est optionnel (un std :: locale) – overcoder

+2

@Overcoder: c'est parce que 'g (str)' immédiatement devient 'g (str, 0)' - l'argument par défaut est juste un code de génération de sucre. –

Répondre

6

arguments par défaut sont un simple outil de génération de code et ne fait pas partie de la signature de la fonction, de sorte que vous ne pouvez pas vraiment autour de ça. Vous pouvez envelopper votre fonction dans un objet fonction, mais c'est exactement ce que bind fait déjà pour vous.

Cependant, en C++ 0x vous pouvez facilement stocker le résultat (et utiliser std::bind) pour faire peut-être un peu le code plus lisible:

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

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

(La raison pour laquelle vous ne voulez pas faire en C++ 98/03 est que le type de retour de bind est quelque chose de plutôt inesthétique, et vous ne feriez à personne une faveur en l'épelant.)

Alternativement, encore en C++ 0x, vous pourriez utiliser un lambda:

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

En outre, si vous avez suivi la norme actuelle, jetez un oeil à bind2nd (en effet, il a des exigences pour les foncteurs - votre g devrait être hérité de binary_function) – cybevnm

+0

@vnm: oui, bon point, une dépendance de moins boost: ' std :: for_each (..., ..., std :: bind2nd (boost :: algorithme :: trim , std :: locale())). –

+1

Merci! Je vais voir si je peux activer C++ 0x pour mon projet actuel. Les Lambdas semblent plus pratiques. – overcoder

Questions connexes