STL for_each lamentano elenco di argomenti
Domanda
Come parte di un compito a casa, siamo tenuti a mappare la presenza di ogni personaggio in una mappa. La nostra funzione si suppone di utilizzare std :: for_each e passare il carattere da valutare.
La mia funzione è:
std::for_each(document_.begin(),
document_.end(),
std::mem_fun(&CharStatistics::fillMap));
document_
è un string
, e la funzione fillMap è definita come
void CharStatistics::fillMap(char ch)
{
ch = tolower(ch);
++chars_.find(ch)->second;
}
chars_
è dichiarato come std::map<char, unsigned int> chars_;
.
Immagino che questo dovrebbe funzionare, ma il compilatore si lamenta ??p>
error C2064: term does not evaluate to a function taking 1 arguments
Il che mi confonde, perché quando guardo la lista degli argomenti
_Fn1=std::mem_fun1_t<void,CharStatistics,char>,
1> _Elem=char,
1> _Traits=std::char_traits<char>,
1> _Alloc=std::allocator<char>,
1> _Result=void,
1> _Ty=CharStatistics,
1> _Arg=char,
1> _InIt=std::_String_iterator<char,std::char_traits<char>,std::allocator<char>>
si guarda bene a me. _Elem è un char e la mia funzione accetta un char. L'iteratore non è altro che un char *
Che cosa sto facendo di sbagliato?
Soluzione
CharStatistics::fillMap
non è una funzione di prendere 1 argomento. di essa la funzione membro e quindi ha implicitamente primo argomento -. puntatore a un'istanza di classe
nel codice:
std::for_each(document_.begin(),
document_.end(),
std::mem_fun(&CharStatistics::fillMap));
for_each
non so su quale istanza si desidera chiamare CharStatistics::fillMap
, non è stato specificato di esso. hai bisogno di impegnare con qualsiasi istanza CharStatistics, per esempio:.
std::bind1st(std::mem_fun(&CharStatistics::fillMap), &char_statistics_instance)
Altri suggerimenti
document_ è una collezione di personaggi?
Ma la funzione è una funzione membro di CharStatistics! Presumibilmente si sta chiamando questo da una funzione di membro di CharStatistics. In questo caso è possibile usare boost :: bind di risolverlo se ciò è consentito:
std::for_each( document_.begin(), document_.end(),
boost::bind( &CharStatistics::fillMap, this, _1 );
Si potrebbe usare std :: bind1st su "questo" che è più complessa in quanto è comunque necessario mem_fun
std::for_each( document_.begin(), document_.end(),
std::bind1st( std::mem_fun(&CharStatistics::fillMap), this ) );
che in realtà è terribilmente complessa ricerca. Ecco perché il nuovo bind è molto meglio!
Se non si è autorizzati a utilizzare boost :: bind e non vi piace la soluzione mem_fun, scrivere il proprio funtore che sovraccarichi operatore () per prendere un char. In questo modo:
struct CharStatsFunctor
{
typedef std::map< char, size_t > map_type;
map_type & mapToFill;
explicit CharStatsFunctor( map_type & m ) : mapToFill( m ) {}
void operator()(char ch ) const
{
++mapToFill[ ::tolower( ch ) ];
}
};
Nella chiamata ciclo
std::for_each( document_.begin(), document_.end(), CharStatsFunctor( chars_ ) );
Nota c'è un errore nella funzione fillMap. La soluzione che ho dato funzionerà.
Fondamentalmente ciò che è sbagliato è che il contenitore ha un tipo di valore char
, e for_each
prevede una funzione che prende un argomento di char
, ma valuta std::mem_fun(&CharStatistics::fillMap)
ad un oggetto funzione che accetta un'istanza di CharStatistics
(sul quale verrà poi chiama fillMap
)
Perché non cambiare semplicemente la vostra funzione:
void CharStatistics::fillMap(std::string const& str)
{
std::string::const_iterator it(str.begin()), end(str.end());
for(; it != end; ++it)
++chars_.find(tolower(*it))->second;
}
Se CharStatistics::fillMap
non è una funzione di membro static, allora avete bisogno di impegnare la chiamata a un'istanza:
CharStatistics instance;
std::for_each(
document_.begin(),
document_.end(),
std::bind1st(
&CharStatistics::fillMap,
&instance
)
);
Inoltre, se non è una funzione membro statica, quindi in realtà ha due argomenti. Il primo è il puntatore this
implicita, e il secondo è il char
. Quindi devi legare due argomenti, utilizzando boost::bind
(o std::bind
se si è in C ++ 0x):
CharStatistics instance;
std::for_each(
document_.begin(),
document_.end(),
boost::bind(
&CharStatistics::fillMap,
&instance,
_1
)
);
for_each
dovrebbe ora vedere l'istanza bind2nd
come oggetto funzione prendendo un argomento (_1
), e l'istanza verrà passata automaticamente.