C++ 循环的简化

C++ 循环的简化,c++,functor,simplify,C++,Functor,Simplify,我有一个函数,它从一个double向量中读取值,将这些值附加到一个字符串中(同时确保每个值之间有一个空格并设置其精度),并返回最终结果,减去最后的空格: std::string MultiplePrintProperties::GetHpitchString() { std::string str; vector< double >::iterator it; for ( it = Vals.begin();

我有一个函数,它从一个double向量中读取值,将这些值附加到一个字符串中(同时确保每个值之间有一个空格并设置其精度),并返回最终结果,减去最后的空格:

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 ); 
}
std::string MultiplePrintProperties::GetHpitchString()
{    
std::字符串str;
向量::对其进行迭代器;
for(it=Vals.begin();
it!=Vals.end();
it++)
{
Ostringstreams;
//将精度设置为小数点后3位
//然后读入字符串
boost::格式fmt(“%.3f”);

s由于您实际上是将double转换为字符串,并将这些字符串附加到stringstream,因此可以使用
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() );
//您的函子,将双精度转换为字符串
结构变换\u一\u双{
std::string运算符()(const double&d)const{
boost::格式fmt(“%.3f”);
返回(fmt%d).str();
}
};
//迭代代码,获取每个值并插入转换后的
//将值导入stringstream。
std::transform(vals.begin(),vals.end())
,std::ostream_迭代器(“”)
,转换_one_double());

您可以使用重载的
运算符()创建一个类。
将引用std::string作为成员。您将声明该类的一个对象,并将该字符串传递到构造函数中,然后将该对象作为第三个参数来为每个。重载运算符()将为每个元素调用,并将文本附加到引用的字符串。

这些天我似乎有点老了。我会这样做:

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; 
}
std::string MultiplePrintProperties::GetHpitchString()
{    
std::字符串str;
向量::对其进行迭代器;
for(it=Vals.begin();
it!=Vals.end();
it++)
{
//将精度设置为小数点后3位
//并将其写入字符串中
char-buf[20];
snprintf(buf,20,“.3f%,*it);
如果(str.length()>0)
str.append(“”);
str.append(buf);
}
返回str;
}

如上所述,实现这一目标的方法很多,但是。。。 这个方法不只是要求有更多的参数和模板化吗? 假设你有

template< class tType >
std::string PrintVectorToArray( const std::vector< tType >& V, const char* Seperator );
模板
std::string printVectorArray(const std::vector&V,const char*分隔符);
然后你可以创造

1 2 3

1,2,3

1.0、2.0、5.0

对于任何可转换为字符串的类型和任何分隔符!
我曾经这样做过,现在发现自己经常使用这种方法。

我建议使用单一的stringstream和单一的格式。这些并不便宜

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;
}

“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++);
}
std::字符串s;
std::vector::iterator i=vals.begin();
如果(i!=vals.end())
{
boost::格式fmt(“%.3f”);
s=str(fmt%*i++);
而(i!=vals.end())
s+=''+str(fmt%*i++);
}

我没有发现您的原始代码过于臃肿或急需简化。但是,我会移动

boost::format fmt("%.3f");

循环外,以确保它们只初始化一次。这也会节省大量的str.append()-ing。我猜xtofl的std::transform()解决方案会有这个问题(不过,对结构初始化一次很容易解决)

如果您正在寻找其他替代方案

 for (it = begin(); it != end(); ++it) {...}
检查哪些选项可以使您以以下方式进行迭代:

std::vector<double> list;
BOOST_FOREACH(double value, list) {
    ...
}
std::向量列表;
BOOST_FOREACH(双倍值,列表){
...
}

为什么要简化它?它是可读的。它看起来足够有效。我想你可以使用map reduce之类的东西,但我看不出有什么理由这样做。原样的代码有一个严重的缺陷。如果向量中没有数据,那么最后的空格(不存在)将被删除。可能会提供很多例外!我认为回报需要包括(fmt%d).str()虽然或类似的东西。是的,它会。纠正了这一点。静态ostringstream在我看来是一个非常糟糕的主意。如果两个线程同时调用此方法呢?Havok,那当然不好。在这种情况下,您将使用一个线程局部变量。您假设float可以容纳20个字符。即使现在这是真的,它在未来的64位、128位或256位体系结构?虽然您的代码将继续工作而不会崩溃,但更隐秘的错误是,结果的截断将在没有警告或错误的情况下发生。您完全正确。即使使用32位浮点,您也可以使用溢出(例如1e20将)。这是简单和彻底之间的折衷。在实践中,我非常确定20位数字就足够了。我认为我们处理字符串是因为结果将是人类可读的。超过20位的数字测试人类可读性的极限。希望作者知道一个Hpitch的极限是什么.嗯,我正在努力说服自己:-(
 for (it = begin(); it != end(); ++it) {...}
std::vector<double> list;
BOOST_FOREACH(double value, list) {
    ...
}