为什么ostream_iterator需要显式声明要输出的对象类型?

xml*_*lmx 10 c++ stream

在当前的C++中,类ostream_iterator的设计如下:

// excerpted from the standard C++

template<class T, ...>
class ostream_iterator
{
public:
    ostream_iterator(ostream_type&);
    ...

    ostream_iterator<T,...>& operator =(const T&);
    ...
};
Run Code Online (Sandbox Code Playgroud)

对我来说,这种设计并不是最理想的.因为用户在声明ostream_iterator时必须指定类型T:ostream_iterator<int> oi(cout);事实上,cout可以将任何类型的对象作为其参数,而不是仅使用一种类型.这是一个明显的限制.

// Below is my own version

// doesn't need any template parameter here
class ostream_iterator
{
public:
    ostream_iterator(ostream_type&);
    ...

    // define a template member function which can take any type of argument and output it
    template<class T> 
    ostream_iterator<T,...>& operator =(const T&);
    ...
};
Run Code Online (Sandbox Code Playgroud)

现在,我们可以使用它如下:

ostream_iterator oi(cout);
Run Code Online (Sandbox Code Playgroud)

我认为它比它更通用,更优雅

ostream_iterator<int> oi(cout);
Run Code Online (Sandbox Code Playgroud)

我对吗?

Cas*_*Cow 1

看来你可能是对的。

让我们看看是否可以构造一个不需要模板参数的 ostream_iterator。

迭代器通过将值复制到其中来工作,因此*iter = x; ++iter; 迭代器通过使operator*返回自身并且++iter在不改变任何状态的情况下返回自身来作弊。“魔力”在于执行输出的operator=。

“cout”必须是 ostream* 类型的类成员。它需要是一个指针,因为迭代器必须是可分配的,因此我们将成员(称为 os)分配给传入的流的地址。

所以我们会这样重载operator=:

template< typename T >
our_ostream_iterator& operator=( const T& t )
{
   (*os) << t;
   if( delim )
      (*os) << delim;
   return *this;
}
Run Code Online (Sandbox Code Playgroud)

请注意,模板化的operator=不应重载比模板更专业的operator=(our_ostream_iterator const&)。

您仍然需要元素类型的模板,因此我们将其称为our_basic_ostream_iterator

ostream_iterator 仍将保留其元素类型的模板类。因此:

template< typename E, typename TR=char_traits<E> >
class our_basic_ostream_iterator : public std::iterator< /*traits here*/ >
{
public:
   typedef E element_type;
   typedef TR traits_type;
   typedef basic_ostream< E, TR > stream_type;
private:
   stream_type * os;
   const E* delim;
public:
   our_basic_ostream_iterator( stream_type s, const E* d = nullptr ) :
      os( &s ), delim( d )
   {
   }

   our_basic_ostream_iterator& operator++() { return *this; }
   our_basic_ostream_iterator operator++(int) { return *this; }
   our_basic_ostream_iterator& operator*() { return *this; }

   template< typename T >
   our_basic_ostream_iterator& operator=( const T& t ); // as above
};
Run Code Online (Sandbox Code Playgroud)

然后当然

typedef our_basic_ostream_iterator<char> our_ostream_iterator;
typedef our_basic_ostream_iterator<wchar_t> our_wostream_iterator;
Run Code Online (Sandbox Code Playgroud)

但所有这些的缺点是,上述内容并不符合迭代器的所有属性,因此它可以传递给任何需要前向迭代器的算法/类。为什么?因为这样的算法应该能够调用iterator_traits来提取元素类型,而上面的类不包含元素类型。

这会导致使用迭代器的算法出现编译时错误,并且可能很难找出原因。