std::getline不接受std::back_insert_iterator。

4
int main() { 
    std::deque<std::string> mydeque;
    std::back_insert_iterator<decltype(mydeque)> myback_insert_iterator(mydeque);
    std::ifstream myifstream("test.txt");
    while(std::getline(myifstream, *myback_insert_iterator)) {
    }
}

我希望将文本文件逐行读入字符串容器中。以下代码会报编译错误:

C2784: 无法从 'std::ifstream' 推断出模板参数 'std::basic_istream<_Elem,_Traits>&'

问题出在哪里?


你应该优先选择使用 std::back_inserter,而不是显式声明一个 back_insert_iterator<T> - pmr
请注意,在迭代器的声明中,您可以使用std::back_inserter(mydeque)而不是使用decltype - 这是一个函数模板,会自动为您推断类型。您可以直接将其传递给您的函数,或者使用auto声明变量,使您的代码更易读。 - Björn Pollex
2个回答

7

尝试:

int main()
{
    std::deque<std::string> mydeque;
    std::ifstream myifstream("test.txt");

    std::string line;
    while(std::getline(myifstream, line)
    {
        mydeque.push_back(line);
    }
}

如果每行只有一个单词,您可以简化为:
int main()
{
    std::deque<std::string> mydeque;
    std::ifstream myifstream("test.txt");

    // Note: istream_iterator<T> uses std::istream& operator>>(std::istream&, T&) to
    //       read data from the stream. If `T` is a std::string this means it will
    //       read a single space separated word.

    std::copy(std::istream_iterator<std::string>(myifstream),
              std::istream_iterator<std::string>(),
              std::back_inserter(mydeque)
             );
}

如果每行包含多个单词,而您想要使用后插入器,则需要定义一个类,在此对象中读取整行以便与迭代器一起使用:

struct Line
{
    std::string data;
    operator std::string const&() const {return data;}

    friend std::istream& operator>>(std::istream& s, Line& dst)
    {
        return std::getline(s, dst.data);
    }
};

int main()
{
    std::deque<std::string> mydeque;
    std::ifstream myifstream("test.txt");

    std::copy(std::istream_iterator<Line>(myifstream),
              std::istream_iterator<Line>(),
              std::back_inserter(mydeque)
             );
}

或者我们可以直接使用构造函数:
int main()
{
    std::ifstream myifstream("test.txt");
    std::deque<std::string> mydeque(std::istream_iterator<Line>(myifstream),
                                    (std::istream_iterator<Line>()));
    // Note: Extra brace required around second iterator here
    //       This is to avoid the problem with the `Most Vexing Parse`
    //       Which would otherwise make this a function declaration

}

那可能会起作用。你有什么想法,为什么解引用的insert_iterator表现与可分配的字符串对象不同?因为*myback_insert_iterator = "abc";实际上可以正常工作。 - Simon1X
1
@Simon1X:back insert iterator是一种输出迭代器。从技术上讲,在对值使用赋值运算符后,必须使用++运算符(请参见输出迭代器页面中的注释3)。不增加赋值后的迭代器是未定义的行为。这归结于输出迭代器没有值类型,因此operator *不返回对std::string的引用(实际类型未定义)。迭代器是根据操作符与预期输出之间的关系来定义的。 - Martin York
@simon1X C++是一种静态类型语言。编译器不了解其行为,只知道语言结构和类型,迭代器不是一个字符串。getline接受字符串作为参数,尽管你需要的操作子集可以应用于该迭代器(或许多其他类型),但编译器会拒绝它,因为无论它如何高呼,它都不是一只鸭子。 - David Rodríguez - dribeas

2

getline 函数需要一个字符串作为参数,而不是输出迭代器。你可以将 myifstream 包装成输入迭代器,并使用 std::copy 函数。像这样:

#include <deque>
#include <fstream>
#include <algorithm>
#include <iterator>

int main() {
    std::deque<std::string> mydeque;
    std::back_insert_iterator<decltype(mydeque)> myback_insert_iterator(mydeque);
    std::ifstream myifstream("test.txt");
    std::istream_iterator<std::string> i_it(myifstream), eos;
    std::copy(i_it, eos, myback_insert_iterator);
}

1
你可以简写为:std::dequestd::string mydeque(std::istream_iteratorstd::string(myifstream), (std::istream_iteratorstd::string())); 但是,停止时不仅限于换行符,还包括空格符。 - Simon1X

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接