我有一个基本上从双向量中读取值的函数,将它们附加到一个字符串(同时确保每个字符串之间的空间并设置它们的精度)并返回最终结果,减去最后的空格:
std::string MultiplePrintProperties::GetHpitchString()
{
std::string str;
vector< double >::iterator it;
for ( it = Vals.begin();
it != Vals.end();
it++ )
{
ostringstream s;
// Set precision to 3 digits after the decimal point
// and read into the string
boost::format fmt( "%.3f " );
s << fmt % *( it );
str.append( s.str() );
}
// Remove last white space and return string
return str.substr( 0, str.length() - 1 );
}
我想知道这段代码是否可以以任何方式简化。我最近一直在调查for_each和functor的使用,但是我们无法弄清楚这些技术如何改进这个特定的例子。
答案 0 :(得分:11)
由于您实际上是将双精度转换为字符串,并将这些字符串附加到字符串流中,因此您可以使用std::transform
:
// your functor, transforming a double into a string
struct transform_one_double {
std::string operator()( const double& d ) const {
boost::format fmt( "%.3f " );
return (fmt % d).str();
}
};
// iteration code, taking each value and inserting the transformed
// value into the stringstream.
std::transform( vals.begin(), vals.end()
, std::ostream_iterator<std::string>( s, " ")
, transform_one_double() );
答案 1 :(得分:4)
这些天似乎我有点老了。我会这样做的:
std::string MultiplePrintProperties::GetHpitchString()
{
std::string str;
vector< double >::iterator it;
for ( it = Vals.begin();
it != Vals.end();
it++ )
{
// Set precision to 3 digits after the decimal point
// and write it into the string
char buf[20];
snprintf( buf, 20, "%.3f", *it );
if (str.length() > 0)
str.append(" ");
str.append( buf );
}
return str;
}
答案 2 :(得分:2)
'fmt'变量应该在循环外声明,因为每次迭代设置格式都很慢而且不需要。也不需要stringstream。所以身体会变成这样的东西:
std::string s;
std::vector<double>::iterator i = vals.begin();
if (i != vals.end())
{
boost::format fmt("%.3f");
s = str(fmt % *i++);
while (i != vals.end())
s += ' ' + str(fmt % *i++);
}
答案 3 :(得分:2)
我没有发现你的原始代码膨胀或迫切需要简化。然而,我会移动
boost::format fmt("%.3f");
和
ostringstream s;
离开循环以确保它们仅被初始化一次。这样可以节省很多str.append()。我猜xtofl的std :: transform()解决方案会有这个问题(虽然通过初始化一次为结构很容易修复)。
如果您正在寻找
的其他替代方案 for (it = begin(); it != end(); ++it) {...}
签出BOOST_FOREACH,这将使您能够以下列方式进行迭代:
std::vector<double> list;
BOOST_FOREACH(double value, list) {
...
}
答案 4 :(得分:1)
您可以创建一个具有重载operator()
的类,该类具有对std :: string的引用作为成员。您将声明此类的对象并将该字符串传递给构造函数,然后将该对象用作for_each的第三个参数。将为每个元素调用重载的operator(),并将文本附加到引用的字符串。
答案 5 :(得分:1)
如上所述,有很多方法可以实现这一目标,但...... 这种方法是不是只是想要一些更多的参数并被模板化? 假设你有
template< class tType >
std::string PrintVectorToArray( const std::vector< tType >& V, const char* Seperator );
然后你可以创建
1 2 3
1,2,3
1.0然后是2.0然后是5.0
任何可转换为字符串和任何分隔符的类型! 我曾经这样做过,现在发现自己经常使用这种方法。
答案 6 :(得分:0)
我建议使用单个字符串流和单一格式。那些并不便宜。
std::string MultiplePrintProperties::GetHpitchString()
{
std::ostringstream s;
// Set precision to 3 digits after the decimal point
static boost::format fmt( "%.3f " );
for ( vector< double >::iterator it = Vals.begin();
it != Vals.end(); it++ )
{
// and read into the string
s << fmt % *( it );
}
// Remove last white space (if present) and return result
std::string ret = s.str();
if (!ret.empty()) ret.resize(ret.size()-1);
return ret;
}
如果我有分析信息证明它仍然是瓶颈,我会考虑使用静态ostringstream:
static std::ostringstream s;
...
std::string ret;
std::swap(ret, s.str());
return ret;