C++ 将字符串向量连接到std::ostream(如boost::Join)

C++ 将字符串向量连接到std::ostream(如boost::Join),c++,ostream,delimited-text,C++,Ostream,Delimited Text,我有一个字符串向量,我想把它输出到流(实际上是文件流)。我想在向量元素之间有一个分隔符。有一种方法可以使用标准的ostream\u迭代器 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 ); std

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

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 );
std::向量strs;
std::ostream\u迭代器out\u文件迭代器(out\u文件,delim);
std::copy(strs.begin()、strs.end()、out\u file\u迭代器);
我不喜欢这种方式,因为每个元素后面都有
delim
文本,但我不需要在最后一个元素后面有
delim
。我想使用类似于
boost::join
的东西。但是,
boost::join
返回的字符串和我的向量太大,无法将其输出到字符串


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

一种有效的方法是分别处理最后一种。但不要认为它很优雅。当然,您可以将丑陋之处封装在自己的
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;
  }
}
assert(strs.size()>0);
std::ostream\u迭代器out\u文件迭代器(out\u文件,delim);
std::copy(strs.begin(),strs.end()-1,out\u file\u迭代器);

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

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;
  }
}
模板
无效打印\u范围(流&s、初始第一、初始最后、字符常量*delim=“\n”){
如果(第一个==最后一个)
返回;
s对于一般解决方案(未测试):


这是一个有函子的想法

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(" , "));
使用名称空间std;
结构添加文件{
add_delim_t(const char*_delim):delim_(_delim),is_first_(true){
字符串运算符()(常量字符串和值){
如果(is_first){is_first=false;返回_val;}否则返回delim_+\u val;
}
私人:
常量字符串delim;
布尔是第一;
};
转换(s.begin()、s.end()、ostream_迭代器(cout)、add_delim_t(“,”);

这个解决方案的问题在于它使用了statefull谓词。理论上它的意思是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>()
);
使用名称空间std;
结构生成器{
typedef字符串结果\ u类型;
生成器(结果类型){u delim):delim({u delim),是第一个{u(真)}
结果_类型运算符(){
如果(!是第一个)
退换货;
is_first_uu=false;
返回“”;
}
私人:
结果型delim;
布尔是第一;
};
模板
结构反向\u plus:公共二进制\u函数{
T运算符()(常数T&_lhs,常数T&_lhs)常数{return(_rhs+_lhs);}
};
//输出到文件流
使改变
(strs.begin()
,strs.end()
,boost::make_function_input_iterator(生成器(“,”),boost::infinite()
,ostream\u迭代器out\u文件迭代器(out\u文件)
,反向_plus()
);

对空范围进行快速测试怎么样?@Benjamin:这一点很好,不过我想我宁愿把它作为对
print\u range
用户施加的先决条件。嗯,我不是在想“断言”。我想把空范围视为完全有效,而不打印任何内容。毕竟,空集在现实世界中很常见。@Benjamin:在那里,我被说服了。:P仔细考虑后,不管我是否特别处理第一个元素,它都会以相同数量的分支测试结束。不,我想你是对的。这个版本中还有一个额外的分支。例如,当范围为1时,将进行初始测试(将失败),然后打印一个元素,然后在for循环中进行测试(将通过)。对于原始版本,将只在for循环中进行测试。不过,我还是更喜欢这个版本。