15

次の関数を検討してください。

void f(const char* str);

stringstream を使用して文字列を生成し、それをこの関数に渡したいとします。1 つのステートメントでそれを実行したい場合は、次のようにします。

f((std::ostringstream() << "Value: " << 5).str().c_str()); // error

これによりエラーが発生します: 'str()' は 'basic_ostream' のメンバーではありません。では、operator<< は ostringstream ではなく ostream を返します。ostringstream にキャストして戻すのはどうですか?

1) このキャストは安全ですか?

f(static_cast<std::ostringstream&>(std::ostringstream() << "Value: " << 5).str().c_str()); // incorrect output

これで、operator<<("Value: ") 呼び出しが判明しました。実際には、ostream の operator<<(void*) を呼び出して、16 進アドレスを出力しています。これは間違っています。テキストが必要です。

2) 一時的な std::ostringstream() の operator<< が ostream 演算子を呼び出すのはなぜですか? 確かに、一時には「ostream」ではなく「ostringstream」のタイプがありますか?

一時的にキャストして、正しいオペレーター呼び出しを強制することもできます!

f(static_cast<std::ostringstream&>(static_cast<std::ostringstream&>(std::ostringstream()) << "Value: " << 5).str().c_str());

これは機能しているようで、「Value: 5」を f() に渡します。

3) 現在、未定義の動作に依存していますか? キャストは珍しいようです。


最良の代替手段は次のようなものであることは承知しています。

std::ostringstream ss;
ss << "Value: " << 5;
f(ss.str().c_str());

...しかし、私はそれを1行で行う動作に興味があります。誰かが (疑わしい) マクロを作りたいとします:

#define make_temporary_cstr(x) (static_cast<std::ostringstream&>(static_cast<std::ostringstream&>(std::ostringstream()) << x).str().c_str())

// ...

f(make_temporary_cstr("Value: " << 5));

これは期待どおりに機能しますか?

4

6 に答える 6

16

一時ストリームを にキャストすることはできませんstd::ostringstream&。形式が正しくありません (コンパイラは、それが間違っていることを通知する必要があります)。ただし、次の方法で実行できます。

f(static_cast<std::ostringstream&>(
  std::ostringstream().seekp(0) << "Value: " << 5).str().c_str());

それはもちろん醜いです。しかし、それがどのように機能するかを示しています。seekpを返すメンバー関数std::ostream&です。これは一般的に書いたほうがいいかもしれません

template<typename T>
struct lval { T t; T &getlval() { return t; } };

f(static_cast<std::ostringstream&>(
  lval<std::ostringstream>().getlval() << "Value: " << 5).str().c_str());

何もせずに , を取る理由はvoid*、それoperator<<がメンバー関数だからです。かかるoperator<<char const*はありません。

于 2010-03-12T13:55:13.440 に答える
3

関数への非 const 参照としてテンポラリを渡すことはできません。そのため、正しいストリーミング演算子が見つからず、代わりに void* 引数を持つものを使用します (これはメンバ関数であるため、テンポラリで呼び出しても問題ありません)。 .

キャスティングで制限を回避するというのは、実はUBな気がしますが、断言はできません。他の誰かがきっと標準を引用するでしょう。

于 2010-03-12T13:47:12.093 に答える
0

one_lined ステートメントが好きな場合は、次のように記述できます。

// void f(const char* str); 
f(static_cast<ostringstream*>(&(ostringstream() << "Value: " << 5))->str());

ただし、コードを次のように維持しやすい方がよいでしょう。

template <typename V>
  string NumberValue(V val)
  {
     ostringstream ss;
     ss << "Value: " << val;
     return ss.str();
  }
f(NumberValue(5));
于 2010-03-12T15:36:14.463 に答える
0

ロギングには、このようなものを少し使用します。

#include <sstream>

using namespace std;

const char *log_text(ostringstream &os, ostream &theSame)
{
  static string ret; // Static so it persists after the call
  ret = os.str();
  os.str(""); // Truncate so I can re-use the stream
  return ret.c_str();
}


int main(int argc, char **argv)
{
  ostringstream  ss;
  cout << log_text(ss, ss << "My first message") << endl;
  cout << log_text(ss, ss << "Another message") << endl;
}

出力:

私の最初のメッセージ

別のメッセージ

于 2012-05-08T10:30:42.347 に答える