1

我想为库中的 std::string 容器提供基于通用行的 IO。基于行,因为字符串可能包含空格。以下代码似乎工作正常,但我不确定这是否是最好的方法,或者它是否会产生一些歧义,我无法掌握。

#define boostForeach BOOST_FOREACH

template< template<typename ELEM, typename ALLOC=std::allocator<ELEM> > class Container >
std::ostream& operator<< (std::ostream& o, Container<std::string>const & container){
  boostForeach(std::string const& str, container) {
    o << str << "\n";
  }
  return o;
}

template< template<typename ELEM, typename ALLOC=std::allocator<ELEM> > class Container >
std::istream& operator>> (std::istream& in, Container<std::string>& container){
  container.clear();
  std::string buf;
  while(getline(in, buf)) {
    if(buf.empty()) break; //stop if empty line found to separate map from other data
    container.insert(container.end(),buf);
  }
  return in;
}

所以问题是:这安全可靠吗?

4

2 回答 2

2

第一个问题是标准容器中模板参数的数量不是标准规定的,这意味着您的代码在任何有任何额外参数的平台上都会失败。

一般来说,我不会为您尚未定义的类型提供运算符重载,尤其是标准容器。原因是你不能正确地做到这一点。特别是您不能在容器所在的命名空间中声明它们,这意味着 ADL 不会神奇地选择正确的重载。如果你想要一个辅助函数,你应该提供一个命名函数,如果需要的话,它会更容易帮助查找。

试试这个:

#include <iostream>
#include <vector>
#include <string>

template < template<typename,typename> class Container >
std::ostream& operator<<( std::ostream& o, Container<std::string> const & c );
namespace A {
   struct S {};
   std::ostream& operator<<( std::ostream& o, S const & );
   void f() {
      std::vector<std::string> v;
      std::cout << v;
   }
}
int main() {
   A::f();
}
于 2012-07-16T22:01:22.797 回答
2

您可以使用以下方法编写输出算法std::copy()

std::copy(container.begin(),
    container.end(),
    std::ostream_iterator<std::string>(o, "\n"));

您可以将输入迭代器用于段落输入,即多行由空行分隔:

class istream_paragraph_iterator: public std::iterator<std::forward_iterator_tag,std::string>{
    std::istream* stream;
    std::string line;
public:

    istream_paragraph_iterator() : stream(0) {}

    istream_paragraph_iterator(std::istream& stream) : stream(&stream) {++*this; //get the first element
    }

    std::string operator*() const {
        return line;
    }

    const std::string* operator->() const {
        return &line;
    }

    istream_paragraph_iterator& operator++() {
        if (stream && (!std::getline(*stream, line) || line.empty()))
            stream = 0;
        return *this;
    }

    istream_paragraph_iterator operator++(int) {
        istream_paragraph_iterator previous(*this);
        ++*this;
        return previous;
    }

    bool operator==(const istream_paragraph_iterator& other) const {
        return stream == other.stream;
    }

    bool operator!=(const istream_paragraph_iterator& other) const {
        return !(*this == other);
    }

};

然后您也可以使用以下方法编写输入算法std::copy()

std::copy(istream_paragraph_iterator(in),
    istream_paragraph_iterator(),
    std::back_inserter(container));

将逻辑分离为迭代器类型可以使输入和输出算法可参数化,因此更通用。在模板库中,这通常是一件好事。我会避免为标准容器添加重载,因为您无法知道它们在每个平台上都做正确的事情;基于迭代器的算法更具可移植性,您不必编写所有template<template<...> class ...>繁琐的代码。

于 2012-07-16T22:02:32.780 回答