简体   繁体   English

加速C ++练习8-5解决方案不明确

[英]Accelerated C++ exercise 8-5 solution not clear

I am stuck at solving Accelerated C++ exercise 8-5 and I don't want to miss a single exercise in this book. 我坚持用8-5解决Accelerated C ++练习,我不想错过本书中的一个练习。

Accelerated C++ Exercise 8-5 is as follows: 加速C ++练习8-5如下:

Reimplement the gen_sentence and xref functions from Chapter 7 to use output iterators rather than putting their entire output in one data structure. 重新实现第7章中的gen_sentencexref函数以使用输出迭代器,而不是将它们的整个输出放在一个数据结构中。 Test these new versions by writing programs that attach the output iterator directly to the standard output, and by storing the results in list <string> and map<string, vector<int> > , respectively. 通过编写将输出迭代器直接附加到标准输出的程序,并将结果分别存储在list <string>map<string, vector<int> >来测试这些新版本。

To understand scope of this question and current knowledge in this part of the book - this exercise is part of chapter about generic function templates and iterator usage in templates. 要理解这个问题的范围和本书这一部分的当前知识 - 本练习是关于通用函数模板和模板中迭代器用法的章节的一部分。 Previous exercise was to implement simple versions of <algorithm> library functions, such as equal, find, copy, remove_copy_if etc. 以前的练习是实现<algorithm>库函数的简单版本,例如equal, find, copy, remove_copy_if等。

If I understand correctly, I need to modify xref function so it: 如果我理解正确,我需要修改xref功能,所以:

  • Use output iterator 使用输出迭代器
  • Store results in map<string, vector<int> > 将结果存储在map<string, vector<int> >

I tried to pass map iterator as back_inserter() , .begin() , .end() to this function, but was not able to compile it. 我试图将map迭代器作为back_inserter() .begin() .end()传递给这个函数,但是无法编译它。 Answer here explains why. 这里的答案解释了原因

xref function as in Chapter 7: xref函数与第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;
}

Split implementation: 拆分实施:

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

Please help to understand what am i missing. 请帮助理解我错过了什么。

I found more details on the exercise, here: https://stackoverflow.com/questions/5608092/accelerated-c-exercise-8-5-wording-help : 我在这里找到了有关练习的更多细节: 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 ) ; 

Frankly, I have to come to the conclusion that that question is ill-posed, specifically where they specified the new interface for xref : xref should result in a map. 坦率地说,我必须得出这样的结论:这个问题是不适定的,特别是在他们指定xref的新接口的情况下:xref应该产生一个映射。 However, using output iterators would imply using std::inserter(map, map.end()) in this case. 但是,在这种情况下,使用输出迭代器意味着使用std::inserter(map, map.end()) While you can write a compiling version of the code, this will not do what you expect since map::insert will simply ignore any insertions with duplicated keys. 虽然您可以编写代码的编译版本,但这不会达到预期的效果,因为map::insert将忽略任何带有重复键的插入。

If the goal of xref is only to link the words to the line number of their first appearance this would still be ok, but I have a feeling that the author of the exercise simply missed this subtler point :) 如果外部参照的目标只是将单词链接到他们第一次出现的行号,这仍然可以,但我有一种感觉,练习的作者只是错过了这个更微妙的点:)

Here is the code anyways (note that I invented a silly implementation for split , because it was both missing and required): 以下是代码(请注意,我发明了一个用于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;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM