2011-12-18 6 views
6

私はAccelerated C++エクササイズ8-5を解決することに固執しており、この本では1つのエクササイズを逃したくありません。次のようにC++のエクササイズ8-5の解決策が明確でない

加速C++エクササイズ8-5は次のとおりです。

は1つのデータ 構造に彼らの全体の出力を置くのではなく、 出力イテレータを使用するように、第7章からgen_sentencexref機能を再実装します。 出力イテレータを標準出力に直接添付し、 の結果をそれぞれlist <string>map<string, vector<int> >に格納することで、これらの新しいバージョンをテストしてください。

本書のこの部分のこの範囲と現時点での知識の範囲を理解するために、この演習はテンプレートの汎用関数テンプレートとイテレータの使用法に関する章の一部です。前の演習では、などequal, find, copy, remove_copy_ifなど<algorithm>ライブラリ関数の簡単なバージョンを実装することでした

私が正しく理解していれば、私は xref機能を変更する必要が

ので:

  • 使用出力イテレータ
  • ストア結果でmap<string, vector<int> >

私はTHIするback_inserter().begin().end()としてマップイテレータを通過しようとしましたコンパイルできませんでした。回答hereが理由を説明します。第7章のように

外部参照機能:

// find all the lines that refer to each word in the input 
map<string, vector<int> > 
    xref(istream& in, 
     vector<string> find_words(const string&) = split) 
{ 
    string line; 
    int line_number = 0; 
    map<string, vector<int> > ret; 

    // read the next line 
    while (getline(in, line)) { 
     ++line_number; 

     // break the input line into words 
     vector<string> words = find_words(line); 

     // remember that each word occurs on the current line 
     for (vector<string>::const_iterator it = words.begin(); 
      it != words.end(); ++it) 
      ret[*it].push_back(line_number); 
    } 
    return ret; 
} 

スプリット実装:

vector<string> split(const string& s) 
{ 
    vector<string> ret; 
    typedef string::size_type string_size; 
    string_size i = 0; 

    // invariant: we have processed characters `['original value of `i', `i)' 
    while (i != s.size()) { 
     // ignore leading blanks 
     // invariant: characters in range `['original `i', current `i)' are all spaces 
     while (i != s.size() && isspace(s[i])) 
      ++i; 

     // find end of next word 
     string_size j = i; 
     // invariant: none of the characters in range `['original `j', current `j)' is a space 
     while (j != s.size() && !isspace(s[j])) 
      ++j; 

     // if we found some nonwhitespace characters 
     if (i != j) { 
      // copy from `s' starting at `i' and taking `j' `\-' `i' chars 
      ret.push_back(s.substr(i, j - i)); 
      i = j; 
     } 

    } 
    return ret; 
} 

私は何をしないのです理解するのに役立ちます。

答えて

4

私はここで、運動の詳細を見つけました:https://stackoverflow.com/questions/5608092/accelerated-c-exercise-8-5-wording-help

template <class Out> 
void gen_sentence(const Grammar& g, string s, Out& out) 

USAGE:

std::ostream_iterator<string> out_str (std::cout, " "); 
gen_sentence( g, "<sentence>", out_str ); 

template <class Out, class In> 
void xref( In& in, Out& out, vector<string> find_words(const string&) = split ) 

USAGE:

std::ostream_iterator<string> out_str (std::cout, " "); 
xref( cin, out_str, find_url ) ; 

率直に言って、私は彼らがxrefのための新しいインターフェイスを指定し、具体的場所、その質問は不良設定されていることを結論に来ている:外部参照は、マップを生じるはずです。ただし、出力イテレータを使用すると、この場合はstd::inserter(map, map.end())が使用されます。コードのコンパイル版を書くことはできますが、map::insertは重複したキーの挿入を無視するだけなので、期待通りのことはできません。

外部参照の目標は、これはまだ大丈夫だろう彼らの初登場の行番号に単語をリンクするだけですが、私は運動の著者は、単純にこの微妙なポイント:)

を逃したという感覚を持っている場合

は、ここで(それは両方とも行方不明だったし、必要なので、私はsplitのための愚かな実装を発明したことに注意してください)とにかくコードです:あなたの答えのための

#include <map> 
#include <vector> 
#include <iostream> 
#include <sstream> 
#include <fstream> 
#include <algorithm> 
#include <iterator> 

std::vector<std::string> split(const std::string& str) 
{ 
    std::istringstream iss(str); 
    std::vector<std::string> result; 
    std::copy(std::istream_iterator<std::string>(iss), 
       std::istream_iterator<std::string>(), 
       std::back_inserter(result)); 

    return result; 
} 

// find all the lines that refer to each word in the input 
template <typename OutIt> 
OutIt xref(std::istream& in, 
     OutIt out, 
     std::vector<std::string> find_words(const std::string&) = split) 
{ 
    std::string line; 
    int line_number = 0; 

    // read the next line 
    while (getline(in, line)) { 
     ++line_number; 

     // break the input line into words 
     std::vector<std::string> words = find_words(line); 

     // remember that each word occurs on the current line 
     for (std::vector<std::string>::const_iterator it = words.begin(); 
      it != words.end(); ++it) 
      *out++ = std::make_pair(*it, line_number); 
    } 

    return out; 
} 

int main(int argc, const char *argv[]) 
{ 
    std::map<std::string, int> index; 

    std::ifstream file("/tmp/test.cpp"); 
    xref(file, std::inserter(index, index.end())); 

#if __GXX_EXPERIMENTAL_CXX0X__ 
    for(auto& entry: index) 
     std::cout << entry.first << " first found on line " << entry.second << std::endl; 
#else 
    for(std::map<std::string, int>::const_iterator it = index.begin(); 
     it != index.end(); 
     ++it) 
    { 
     std::cout << it->first << " first found on line " << it->second << std::endl; 
    } 
#endif 

    return 0; 
} 
+0

感謝。残念ながら、 'split'実装を投稿していません。私はそれを私の質問に加えます。状況は 'make_pair'関数に慣れていないことです。少しの検索で、 'make_pair'は本の最後に書かれたライブラリ要約にしか書かれていないことが分かりました。 – user1104456

+0

make_pairはテンプレートメソッドです。あなたが 'std :: pair 'のような型を持っていれば、 'std :: pair ではなく' make_pair( "hello"、5); ' 、int>( "hello"、int) 'これは、あなたが作りたいペアの種類を推測するものです。 – matiu

+0

さらに2つの注意。 1)xref関数はもともと、文字列とintのベクトルを含む 'map > 'という各行の単語が返された。 (答えの中の添付されたコードは行の単語だけが最初に見つかった)2)出力イテレータを直接標準出力に付けることができるはずです。私はそれをどうやって行うのかわからないのですか解決策を別々に実装すべきですか? – user1104456

関連する問題