2011-01-20 25 views
2

宿題の一部として、マップ内の各文字のオカレンスをマップすることになっています。私たちの関数はstd :: for_eachを使い、評価対象の文字を渡すことになっています。STL for_each引数リストについて文句を言う

std::for_each(document_.begin(), 
       document_.end(), 
       std::mem_fun(&CharStatistics::fillMap)); 

document_stringあり、かつfillMap機能がstd::map<char, unsigned int> chars_;として宣言され

void CharStatistics::fillMap(char ch) 
{ 
    ch = tolower(ch); 
    ++chars_.find(ch)->second; 
} 

chars_ように定義されています

私の関数です。

私は、これは動作するはず把握、私は引数リスト

_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>> 

を見たとき、それは私には正常に見えるため、コンパイラは、私を混乱させる

error C2064: term does not evaluate to a function taking 1 arguments 

を不平を言っています。 _Elemはcharで、私の関数はcharを受け入れます。イテレータは他にはありません。char *

私は間違っていますか?

答えて

6

CharStatistics::fillMapは、1つの引数を取る関数ではありません。それはメンバ関数なので、暗黙の第1引数 - クラスインスタンスへのポインタを持ちます。コード内

std::for_each(document_.begin(), 
       document_.end(), 
       std::mem_fun(&CharStatistics::fillMap)); 

for_eachは、あなたがそれを指定していない、あなたがCharStatistics::fillMapを呼び出したいのですがどのインスタンスに知りません。あなたは、例えば、任意のCharStatisticsインスタンスとそれをバインドする必要があります。

std::bind1st(std::mem_fun(&CharStatistics::fillMap), &char_statistics_instance) 
1

CharStatistics::fillMapは、静的メンバ関数ではない場合、あなたは、インスタンスへの呼び出しをバインドする必要があります。

CharStatistics instance; 
std::for_each(
    document_.begin(), 
    document_.end(), 
    std::bind1st(
     &CharStatistics::fillMap, 
     &instance 
    ) 
); 

さらに、それはだ場合静的メンバー関数ではない場合、実際には2つの引数があります。最初は暗黙のthisポインターで、2番目のポインターはcharです。 (あなたがC++ 0xの上にある場合やstd::bind)だから、boost::bindを使用して、二つの引数をバインドする必要があります。

CharStatistics instance; 
std::for_each(
    document_.begin(), 
    document_.end(), 
    boost::bind(
     &CharStatistics::fillMap, 
     &instance, 
     _1 
    ) 
); 

for_eachは今、一つの引数(_1を)取っ関数オブジェクトとしてbind2ndインスタンスを参照してください、とすべきですインスタンスは自動的に渡されます。

+0

bind2ndは何が書かれていることは、ブースト::バインドまたはのstd ::バインド(新規格)構築物である、ことをしないだろうし。 bind2ndは関数とパラメータの2つのパラメータしか取らないので、コンパイルエラーが発生します。 – CashCow

+0

@CashCow:ああ、あなたは正しい。私はいつも 'boost :: bind'を使います。編集されました。 –

2

document_は文字の集まりですか?

しかし、この関数はCharStatisticsのメンバー関数です!おそらく、あなたはCharStatisticsのメンバー関数からこれを呼び出しています。あなたはブーストを使用することができ、その場合には::それが許可されている場合は、それを解決するためにバインド:

std::for_each(document_.begin(), document_.end(), 
    boost::bind(&CharStatistics::fillMap, this, _1); 

あなたはSTDを使用することができます::あなたはまだ

std::for_each(document_.begin(), document_.end(), 
     std::bind1st(std::mem_fun(&CharStatistics::fillMap), this)); 
をmem_fun必要があるとして、より複雑である「この」でbind1st

実際には恐ろしく複雑です。それが新しいバインドがずっと優れている理由です!

boost :: bindの使用が許可されておらず、mem_funソリューションが気に入らない場合は、operator()をオーバーロードしてcharを取得する独自のファンクタを作成します。このように:ループコール

std::for_each(document_.begin(), document_.end(), CharStatsFunctor(chars_)); 

ノートで

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) ]; 
    } 
}; 

あなたfillMap機能にエラーがあります。私が与えた解決策はうまくいくでしょう。

+0

+1 ...私はそのような仕事のためにほぼ独占的にファンクターを使います。彼らははるかに無痛です。 –

1

は基本的に間違っているものを、あなたのコンテナが値型charを有することである、とfor_eachcharの引数を取る関数を想定していますが、std::mem_fun(&CharStatistics::fillMap)は(それが、その後呼ぶにCharStatisticsのインスタンスを取る関数オブジェクトに評価しますfillMap

なぜ単にあなたの関数は変更しない:

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; 
} 
関連する問題