0

代码来自C++ Primer(3 third)。错误是:

*filterString.cpp:在函数 'int main()' 中:filterString.cpp:32:68:错误:无法将 '__gnu_cxx::__normal_iterator*, std::vector > >' 转换为 'std::string* {aka std ::basic_string }' 在初始化

请帮我分析错误,谢谢。

代码:

#include <string>
#include <algorithm>
#include <iterator>
#include <vector>
#include <iostream>

using namespace std;

template <class InputIterator>
void filter_string(InputIterator first, InputIterator last, string filt_elems =  string("\",?.")) {
    for (; first != last; first++){
        string:: size_type pos = 0;
        while ((pos = (*first).find_first_of(filt_elems, pos)) != string::npos)
            (*first).erase(pos, 1);
    }
}

bool length_less (string s1, string s2) {
return s1.size() < s2.size();
}

int main() {
    istream_iterator<string> input(cin), eos;
    vector<string> text;

    copy(input, eos, back_inserter(text));

    string filt_elems("\",.?;:");
    filter_string(text.begin(), text.end(), filt_elems);
    int cnt = text.size();

    string *max = max_element(text.begin(), text.end(), length_less);
    int len = max->size();

    cout << "The number of words read is " << cnt << endl;
    cout << "The longest word has a length of " << len << endl;
    cout << "The longest word is " << *max << endl;

    return 0;
}
4

3 回答 3

1

在第 32 行,

std::max_element(text.begin(), text.end(), length_less);

此函数返回一个前向迭代器,该迭代器指向搜索范围内最大元素的第一次出现的位置,而不是字符串。

你可以做什么而不是这一行:

string *max = max_element(text.begin(), text.end(), length_less);

你必须这样做,

//First find the index of the max_element , by subtracting the forward iterator you get from calling max_element from the iterator for first element .

       int index=max_element(text.begin(), text.end(), length_less) - text.begin();

//And then find string stored on that index.

       string *max = text.at(index);
于 2012-10-27T01:56:57.443 回答
0

好的,所以我过火了。这是我认为使用 lambdas 和 auto 的更现代的解决方案。我把它留给其他人来决定它是否更容易理解。

#include <algorithm>
#include <iostream>
#include <iterator>
#include <ostream>
#include <string>
#include <vector>

using namespace std;

template <class InputIterator>
void filter_string(InputIterator first, InputIterator last, 
                   const string filt_elems = const string("\",?.")) 
{
    for_each(first, last, 
        [filt_elems](string& s)
        {
            s.erase(
                // Shift valid characters up before erasing the undesirable
                remove_if(s.begin(), s.end(), 
                    [filt_elems](string::value_type c)
                    { return filt_elems.find_first_of(c) != string::npos; }), 
                s.end());
        });
}

int main()
{
    istream_iterator<string> input(cin);
    istream_iterator<string> eos;

    vector<const string> words;
    copy(input, eos, back_inserter(words));

    const string filt_elems("\",.?;:");
    filter_string(words.begin(), words.end(), filt_elems);
    const int count = words.size();

    // Get a reference to the longest word
    const auto& max_word = *max_element(words.cbegin(), words.cend(), 
        [](const string& lhs, const string& rhs)
        { return lhs.size() < rhs.size(); });
    const int length = max_word.size();

    cout << "The number of words read is " << count << endl;
    cout << "The longest word has a length of " << length << endl;
    cout << "The longest word is " << max_word << endl;

    return 0;
}
于 2012-10-27T05:33:11.200 回答
0

这是有趣的。迭代器的行为很像指针,但不完全一样。特别是,您不能将迭代器转换为指针。

但是,您可以更改此代码以使用迭代器作为一种 string* 指针:

vector<string>::iterator max = max_element(text.begin(), text.end(), length_less);

这声明 max 不是指向字符串的指针,而是指向字符串向量的迭代器,这是 max_element 算法在应用于字符串向量时返回的内容。

您也可以使用指针,但这是一个坏习惯。只是为了测试这个想法,你可以:

string *max = &*max_element(text.begin(), text.end(), length_less);

*max_element(...) 返回对返回的迭代器指向的字符串的引用(就像取消引用真实指针一样)并 & 创建指向该字符串的 (string*) 指针。

这会带来麻烦,因为向量的结构修改可能会悄悄地使该指针无效。指针的后续使用会将“随机”内存视为字符串对象。更糟糕的是,它可能在您的测试期间工作,并且在软件交付之前不会失败!

一个体面的迭代器实现应该检测到失效并抛出异常。可预测的失败比随机崩溃要好。

于 2012-10-27T02:51:28.307 回答