2014-01-07 136 views
1

我使用istream_iterator从我的文件中插入内容。我也使用std::copy算法。为什么不推导模板参数?

因此,我们知道istream_iterator接受一个流作为参数:

std::istream_iterator<int> it = file; 

我可以通过流,但为什么在这里不工作?

#include <fstream> 
#include <vector> 

int main() 
{ 
    std::ifstream infile("in.txt"); 
    std::vector<int> v; 

    std::copy(infile, std::istream_iterator<int>(), std::back_inserter(v)); 
} 

我必须做这样的:

std::copy(std::istream_iterator<int>(infile), std::istream_iterator<int>(), std::back_inserter(v)); 

但是这看起来很详细,我觉得自己是一个更好的方式做我在做什么...

+0

@juanchopanza'infile',但我做了一个错字。 – user2030677

+1

对函数模板的调用不执行参数的隐式用户定义转换。 'std :: copy'是一个函数模板,而stream-to-iterator是用户定义的转换。 –

+0

这是使用迭代器代替范围的C++标准库的许多缺点之一。现在大家都知道,但现在已经有很多代码很难改变。 –

回答

2

问题是std::copy期望从传递的对象中得到什么。算法std::copy需要迭代器进行操作。更确切地说,前两个参数必须是“InputIterator”来读取(开始和结束),也就是说,这两个对象必须满足some "concept"

可悲的是,IO流在C++不自动履行InputIterator的概念(也结束迭代器仍然会丢失),但是只有当你std::istream_iterator<T>实例包他们,而结束迭代是象征使用实例定义而不指向流。

你可以环绕std::copy它接受的,而不是两个迭代器(所以这也省去了命名结束迭代器)的输入流:

template <class T, 
      class OutputIt /* deduced */, 
      class CharT /* deduced */> 
OutputIt copy_from_istream(std::basic_istream<CharT> & stream, OutputIt out) { 
    return std::copy(
     std::istream_iterator<T, CharT>(stream), 
     std::istream_iterator<T>(), 
     out 
    ); 
} 

使用,这是现在很简单:

copy_from_istream<int>(infile, std::back_inserter(v)); 

Live Demo

1

这是怎样的std::copy相关超载声明:

template< class InputIt, class OutputIt > 
OutputIt copy(InputIt first, InputIt last, OutputIt d_first); 

此功能模板化,它会推断由下式给出该参数的类型。在你的情况下,第一个参数是std::basic_ifstream<...>,因为第二个参数不匹配,你会得到一个编译时错误。

这就是为什么你需要明确的类型。编译器不会知道你的意思。

这样做是提供实际的模板参数明确的短方式:

v.assign<std::istream_iterator<int>>(infile, {}); 
0

尝试使用vector::assign()代替copy()算法:

v.assign(std::istream_iterator<int>(infile), std::istream_iterator<int>())