2011-12-18 42 views
6

我一直在解決加速C++練習8-5,我不想錯過本書中的單個練習。加速C++練習8-5解決方案不清晰

加速C++練習8-5如下:

從第7章重新實現gen_sentencexref功能使用 輸出迭代而不是將它們的整個輸出在一個數據 結構。通過編寫將 輸出迭代器直接附加到標準輸出的程序並將 結果分別存儲在list <string>map<string, vector<int> >中來測試這些新版本。

爲了解這個問題的範圍和本書的這一部分的當前知識 - 本練習是關於泛型函數模板和模板中迭代器使用的章節的一部分。上一頁演習旨在落實<algorithm>庫函數的簡單版本,如equal, find, copy, remove_copy_if

如果我理解正確的話,我需要修改xref功能,因此它:

  • 使用輸出迭代
  • 商店的結果map<string, vector<int> >

我試圖通過地圖迭代器爲back_inserter().begin().end()到THI s函數,但無法編譯它。回答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) 

用法:

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 ) 

用法:

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 '它更容易使用:'make_pair(「hello」,5);'而不是:'std :: pair (「hello」,int)'這種類型推斷你想要做什麼樣的配對。 – matiu

+0

還有兩個注意事項。 1)xref函數最初返回'map >'包含int的字符串和向量,每行都出現在其上。 (答案中的附加代碼只打印出第一個行字)2)我應該可以將輸出迭代器直接附加到標準輸出。要麼我不知道該怎麼做,或者解決方案應該不同地實施? – user1104456