2

基本的に 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 ); 
}

このコードを何らかの方法で単純化できるかどうかを調べたいと思います。私は最近、特に for_each とファンクターの使用を調査していますが、これらの手法がこの特定の例をどのように改善できるかを理解できていません。

4

7 に答える 7

11

std::transform実際に double を文字列に変換し、これらの文字列を文字列ストリームに追加しているので、そのために使用できます。

// 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() );
于 2009-09-09T12:19:36.800 に答える
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; 
}
于 2009-09-09T12:42:52.033 に答える
2

元のコードが肥大化していたり​​、単純化が切実に必要であるとは思いませんでした。しかし、私は移動します

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

ostringstream s;

ループから外れて、一度だけ初期化されるようにします。これにより、str.append()-ingも大幅に節約できます。xtoflのstd::transform()ソリューションにはこの問題があると思います(ただし、構造体に対して一度初期化することで簡単に修正できます)。

あなたが他の選択肢を探しているなら

 for (it = begin(); it != end(); ++it) {...}

BOOST_FOREACHをチェックしてください。これにより、次の方法で反復処理できます。

std::vector<double> list;
BOOST_FOREACH(double value, list) {
    ...
}
于 2009-09-09T15:40:50.337 に答える
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

文字列に変換可能なすべてのタイプと任意のセパレーターに!私はかつてこの方法でそれを行いましたが、今ではこの方法を頻繁に使用しています。

于 2009-09-09T13:00:36.903 に答える
1

operator()メンバーとして std::string への参照を持つオーバーロードされたクラスを作成できます。このクラスのオブジェクトを宣言し、文字列をコンストラクターに渡し、そのオブジェクトを for_each の 3 番目のパラメーターとして使用します。各要素に対してオーバーロードされた operator() が呼び出され、テキストが参照文字列に追加されます。

于 2009-09-09T12:35:22.150 に答える
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;
于 2009-09-09T13:55:00.723 に答える