将字符串的向量连接到std::ostream(类似于boost::Join)

Join vector of strings to std::ostream (like boost::join)

本文关键字:ostream 类似于 boost Join std 字符串 向量 连接      更新时间:2023-10-16

我有一个字符串向量,我想把它输出到流(实际上是文件流)。我想在矢量元素之间有一个分隔符。有一种方法可以使用标准ostream_iterator

std::vector <std::string> strs;
std::ostream_iterator<std::string> out_file_iterator ( out_file, delim );
std::copy ( strs.begin(), strs.end(), out_file_iterator );

我不喜欢这种方式,因为每个元素后面都有一个delim文本,但我不需要在最后一个元素后面有delim。我想用类似boost::join的东西。然而,boost::join返回字符串,而我的向量太大,无法将其输出到字符串。

实现我的目标最优雅的方式是什么?

对于通用解决方案(未经测试):

template<class T>
class ostream_join_iterator {
public:
    // Construct like an ostream_iterator.
    ostream_join_iterator(std::ostream& stream,
        const std::string& delimiter = "")
        : stream(stream), delimiter(delimiter), first(true) {}
    // Behave like an output iterator.
    ostream_join_iterator& operator++()    { return *this; }
    ostream_join_iterator& operator++(int) { return *this; }
    ostream_join_iterator& operator*()     { return *this; }
    // Output a delimiter before all but the first element.
    template<class T>
    ostream_join_iterator& operator=(const T& value) {
        if (!first) {
            stream << delimiter;
        } else {
            first = false;
        }
        stream << value;
        return *this;
    }
private:
    std::ostream& stream;
    const std::string delimiter;
    bool first;
};

您可以像使用常规std::ostream_iterator:一样使用它

std::copy(strings.begin(), strings.end(),
    ostream_join_iterator<std::string>(file, delimiter));

一种工作方式是分别处理最后一个。但不要认为它非常优雅。当然,您可以将丑陋封装在自己的join函数中。

assert(strs.size() > 0);
std::ostream_iterator<std::string> out_file_iterator ( out_file, delim );
std::copy ( strs.begin(), strs.end()-1, out_file_iterator );
out_file << strs.back();

最优雅的是编写自己的循环。或者一个单独的函数。

template<class Stream, class InIt>
void print_range(Stream& s, InIt first, InIt last, char const* delim = "n"){
  if(first == last)
    return;
  s << *first++;
  for(; first != last; ++first){
    s << delim << *first;
  }
}

这是一个带有函子的想法

using namespace std;
struct add_delim_t {
  add_delim_t(const char *_delim) : delim_(_delim), is_first_(true) {}
  string operator () (const string &_val) {
    if (is_first_) { is_first_ = false; return _val; } else return delim_ + _val;
  }
private:
  const string delim_;
  bool is_first_;
};
transform(s.begin(), s.end(), ostream_iterator<string>(cout), add_delim_t(" , "));

这个解决方案的问题是它使用了有状态谓词。理论上它的意思是UB。

Boost函数输入迭代器有一个想法

using namespace std;
struct generator {
  typedef string result_type;
  generator(result_type _delim) : delim_(_delim), is_first_(true) {}
  result_type operator () () { 
    if (!is_first_)
      return delim_; 
    is_first_ = false; 
    return ""; 
  }
private:
  result_type delim_;
  bool is_first_;
};
template<class T>
struct reverse_plus : public binary_function<T, T, T> {
  T operator()(const T& _lhs, const T& _rhs) const { return (_rhs + _lhs); }
};
// output to file stream
transform
( strs.begin()
, strs.end()
, boost::make_function_input_iterator(generator(" , "), boost::infinite())
, ostream_iterator<string> out_file_iterator(out_file)
, reverse_plus<string>()
);