【问题标题】:istream_iterator invalid when using std::copy使用 std::copy 时 istream_iterator 无效
【发布时间】:2016-03-21 14:59:25
【问题描述】:

我正在尝试将一些 intsstdin 复制到 vector。我的代码可以工作,但我不确定为什么在copy 的第二个参数之后需要()。我的意思是istream_iterator<int>() 调用中的istream_iterator<int>() 参数。

代码在这里...

#include <iterator>
#include <vector>
#include <iostream>

using std::vector;
using std::copy;
using std::cin;
using std::istream_iterator;

int main()
{   
     vector<int> nums;
     copy(istream_iterator<int>(cin), istream_iterator<int>(), back_inserter(nums)); // why do I need the empty brackets after the 2nd argument?

     return 0;
}   

如果我删除括号,我会从编译器中得到一个错误,但是如果我将我的代码稍微修改为下面的代码,我的程序就可以正常工作。

int main()
{   
     vector<int> nums;
     istream_iterator<int> end; // no brackets used here
     copy(istream_iterator<int>(cin), end, back_inserter(nums)); 

     return 0;
}  

我来自 Java 背景,所以空括号仅表示您使用了空构造函数。第一个代码 sn-p 违背了我的理解,根据我对 C++ 的理解,如果你想使用一个空的构造函数,你只会错过 () 但这里不是这种情况

帮助!

【问题讨论】:

    标签: c++ iterator copy stdin


    【解决方案1】:

    线

    copy(istream_iterator<int>(cin), istream_iterator<int>, back_inserter(nums));
    

    毫无意义。 istream_iterator&lt;int&gt; 是类型而不是对象。您需要使用() 来创建istream_iterator&lt;int&gt; 类型的未命名的、临时的、默认构造的对象。

    使用

    istream_iterator<int> end;
    

    您声明了一个istream_iterator&lt;int&gt; 类型的对象,并且不需要括号,因为它是默认构造的,没有它们。事实上,如果你使用了括号,比如:

    istream_iterator<int> end();
    

    那么您将遇到most vexing parse 问题,而end 现在将是一个不接受任何内容并返回istream_iterator&lt;int&gt; 的函数。

    【讨论】:

    • 为什么没有为我构建copy 调用默认值中的无括号版本?
    • @CSSStudent 因为您没有创建变量。你刚刚命名了一个类型。 istream_iterator&lt;int&gt; end; 表示创建一个变量名称 end 类型为 istream_iterator&lt;int&gt;istream_iterator&lt;int&gt; 只是一个类型
    【解决方案2】:

    我的代码可以运行,但我不确定为什么在复制的第二个参数之后需要()

    您需要它们在适当的位置构造一个迭代器,而不是声明一个单独的变量来表示输入流的过去。如果你写

    istream_iterator<int>
    

    没有括号,那将是一个类型名称。使用括号调用默认构造函数:

    istream_iterator<int>()
    

    一个istream_iterator&lt;int&gt; 对象在原地构造,并作为第二个参数传递给std::copy。按照惯例,istream_iterator&lt;T&gt; 的默认构造函数为您提供了一个迭代器的实例,该实例发出一个流结束后的信号。

    【讨论】:

    • 如果我有一个vector&lt;int&gt; nums; 是否意味着我有一个类型名称但没有调用构造函数?
    • @CSSStudent 不,它没有,因为您将在声明的上下文中使用vector&lt;int&gt;,而不是在函数调用的上下文中。 vector&lt;int&gt; nums 是一个声明,而copy(istream_iterator&lt;int&gt;(cin), istream_iterator&lt;int&gt;, back_inserter(nums)) 是一个函数调用。
    • @CSSStudent 使用类型声明变量意味着调用默认构造函数。使用类型作为函数参数并不意味着什么,因为它在语义上是非法的。
    • 对,我明白你的意思。对我来说,您错过 () 似乎很奇怪,具体取决于您计划在哪里使用该对象(来自 Java)
    • @CSSStudent 这是因为Java比C++更明确:当你写ArrayList&lt;Integer&gt; x时,Java根本不会初始化x,需要你写new ArrayList&lt;Integer&gt;()。 C++ 允许您跳过new、类型和括号。它还可以让您在进行函数调用时删除new,从而稍微缩短一些内容(以降低可读性为代价,至少在我看来)。
    【解决方案3】:

    这可能会令人困惑,但这两种情况都是通过默认构造函数创建对象。对于第一种情况,您必须使用(),对于第二种情况,您不能使用()

    istream_iterator&lt;int&gt;() 默认构造函数创建一个临时对象。如果没有()istream_iterator&lt;int&gt; 只是一个类型名称,没有意义,因为它是预期类型的​​实例。

    istream_iterator&lt;int&gt; end; 默认构造函数也会创建一个命名对象。这里不能使用(),否则会变成函数声明,不带参数返回istream_iterator&lt;int&gt;。见Most vexing parse

    【讨论】:

    • 啊,这说明为什么在声明对象时不包含()
    • @CSSStudent 所以第一种情况你必须使用,第二种情况你不能使用()。希望答案中的解释可以帮助您区分它们。
    猜你喜欢
    • 1970-01-01
    • 2020-12-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-19
    • 2015-01-05
    • 1970-01-01
    • 2011-11-09
    相关资源
    最近更新 更多