-1

私はいくつかの Ising モデル (1 または -1 の格子) のシミュレーションを行っていますが、ファイルを使用したくありません (ここでは詳細には立ち入らないでください:D だと思います)。つまり、文字列ストリームを使用してデータとデータのファイル名をフォーマットし、それらをbashで分離しています。コード例を示します

#include <stdio.h>
#include <stdlib.h>
#include <string.h>    
#include <iostream>
#include <sstream>
#include <string>    
using namespace std;
void print2bash(string file, string data);

int main(int argc, char *argv[]){

    int i, j, n = atoi(argv[1]);
    // I want to put this outside main() {
    stringstream ssbash;    ssbash.clear(); ssbash.str(""); 
    stringstream ssfile;    ssfile.clear(); ssfile.str("");
    //} 
    //  So I don't have to do ss.clear and ss.str("") every time before using them

    ssfile << "this_" << n << "_is_the_filename.dat" << endl;
    for(i = 0; i < n ; i++){
        for(j = 0; j < n; j++)
            ssbash << i*n+j << "\t";
        ssbash << endl;
    }

    print2bash( ssfile.str(), ssbash.str() );

    return 0;
}
// print2bash(); prints string data; to string file; 
//               This will be used to separate data 
//               afterwards ( i.e. ./Ising.o <arguments> | bash )  
void print2bash(string file, string data){

    stringstream ssbash;    ssbash.clear(); ssbash.str(data);       
    stringstream output;    output.clear(); output.str("");
    string line;

    output << "for((i=0;i<1;i++)) do "<< endl; // Buffer all to bash at once
    while( getline(ssbash,line) )
        output << "    echo \"" << line << "\";" << endl;

    output << "done >> " << file; // Appending
    cout << output.str() << endl;

    ssbash.clear(); ssbash.str("");

    return ;
}

この「sstreams.o」プログラムの通常の出力は次のようになります。

~work/Ising$ ./sstreams.o 5
for((i=0;i<1;i++)) do 
    echo "0 1 2 3 4 ";
    echo "5 6 7 8 9 ";
    echo "10 11 12 13 14 ";
    echo "15 16 17 18 19 ";
    echo "20 21 22 23 24 ";
done >> this_5_is_the_filename.dat

あなたはその考えを正しく理解していますか?この思考の流れから、私が実際に書いている./sstreams.o 10 | bashのは、きれいにファイルを分けられるようにすることです。しかし、問題は次のとおりです。

print2bash() を使いたいたびにこの行を書くのにうんざりしています (皮肉なことです!)

stringstream ssbash;    ssbash.clear(); ssbash.str(""); 
stringstream ssfile;    ssfile.clear(); ssfile.str("");

そのため、グローバル変数として配置したいと思いssます (これがそれほどひどいものかどうかわからないので、コンパイラーはそれを許可しません: 私はただの物理学者です)。したがって、s (および) のstd::stringstream後に ss 変数を記述しても、エラーが発生します。#includeusing namespace std

error: ‘ssbash’ does not name a type
error: ‘ssbash’ does not name a type
error: ‘ssfile’ does not name a type
error: ‘ssfile’ does not name a type

コンパイラから。あなたがミーを助けてくれることを願っています。


編集:[解決済み]

stringstream問題は、メンバーがコンテキストから外れてmain()いるために失敗したことを宣言したい場合clearstrそれらを使用できないことでした。stringstreamそれに加えて、 @jpalecek と @umlaeute が指摘したように、s は空のコンテンツで作成されるため、この使用は不要でした。

stringstreamメインから sを宣言し、目的の結果を得るためにclear()+ str("")onを含めました。print2bash()

#include <stdio.h>
#include <stdlib.h>
#include <string.h>    
#include <iostream>
#include <sstream>
#include <string> 
#include <vector>

using namespace std;

stringstream ssbash, ssfile;

void print2bash(string file, string data);

int main(int argc, char *argv[]){

    int i, j, n = atoi(argv[1]), p, np = atoi(argv[2]);
    vector< vector<int> > chain;    chain.resize(n*n);

    for( p = 0; p < np; p++){

        ssfile << "chain_p="<< p << "_filename.dat" << endl;
        for(i = 0; i < n ; i++){
            for(j = 0; j < n; j++){

                chain[p].push_back( i*n + j );
                ssbash << i*n+j << "\t";
            }
            ssbash << endl;
       }
       print2bash( ssfile.str(), ssbash.str() );
    }

    return 0;
}
void print2bash(string file, string data){

    ssbash.str(data);
    stringstream output;
    string line;

    output << "for((i=0;i<1;i++)) do "<< endl; // Buffer all to bash at once
    while( getline(ssbash,line) )
       output << "    echo \"" << line << "\";" << endl;

    output << "done >> " << file; // Appending 
    cout << output.str() << endl;

    ssfile.clear(); ssfile.str("");
    ssbash.clear(); ssbash.str("");

    return ;
}

の通常の出力./sstreams.o

~/work/Ising$ ./sstreams.o 4 2
for((i=0;i<1;i++)) do 
    echo "0 1   2   3   ";
    echo "4 5   6   7   ";
    echo "8 9   10  11  ";
    echo "12    13  14  15  ";
done >> chain_p=0_filename.dat

for((i=0;i<1;i++)) do 
    echo "0 1   2   3   ";
    echo "4 5   6   7   ";
    echo "8 9   10  11  ";
    echo "12    13  14  15  ";
done >> chain_p=1_filename.dat

すべてに感謝

4

2 に答える 2

3

電話する必要はありません

ssbash.clear(); ssbash.str("");

stringstreamオブジェクトは、空のコンテンツで自動的に作成されるためです。それはあなたに

stringstream ssbash;
stringstream ssfile;

それはグローバルな宣言かもしれませんが、それはあなたを助けないので、それをしないでください。使用するたびにクリアする必要があります。

宣言を何度も繰り返すのが嫌なら、マクロで置き換えることができます

#define DECLARE_STREAMS \
  stringstream ssbash; \
  stringstream ssfile;

以上

#define DECLARE_STREAMS(a, b) \
  stringstream a; \
  stringstream b;

このように使用されます:DECLARE_STREAMS(ssbash, ssfile)

しかし、最良の(そして最もクリーンな)解決策は、データを単一の関数にフォーマットするコードをリファクタリングすることです。そうすれば、ストリーム宣言を繰り返すことを心配する必要はありません。

ところで、C ++でファイルに書き込む代わりに、書き込みを行うスクリプトを発行するのはなぜですか。

于 2012-06-04T13:55:48.810 に答える
2

C / C ++では、関数の外部でコードを実行することは禁止されています(変数の宣言/定義は別として)。

したがって、以下は違法です。

int main(int argc, char**argv) {
   return 0;
}
stringstream ssbash; // OK
ssbash.clear(); // ouch; procedural programming outside of context
ssbash.str(""); // ouch; procedural programming outside of context

clear()とstr()を呼び出す必要がある場合、初期化関数で呼び出す必要があります

static stringstream ssbash, ssfile;
void initSS(void) {
   ssbash.clear(); ssbash.str("");
   ssfile.clear(); ssfile.str("");
}

int main(int argc, char**argv) {
   initSS();
   // ....
   return 0;
}
于 2012-06-04T13:55:51.277 に答える