代码之家  ›  专栏  ›  技术社区  ›  AshleysBrain

在单个语句中将临时stringstream转换为c\u str()

  •  14
  • AshleysBrain  · 技术社区  · 16 年前

    考虑以下功能:

    void f(const char* str);
    

    假设我想使用stringstream生成一个字符串并将其传递给这个函数。如果我想用一句话来表达,我可以试试:

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

    这会产生错误:“str()”不是“basic\u ostream”的成员。好的,所以操作员<&书信电报;是否返回ostream而不是ostringstream-如何将其转换回ostringstream?

    1) 这个石膏安全吗?

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

    现在有了这个,操作员就有了<<(“Value:“)call,它实际上是在调用ostream的操作符<<(void*)并打印十六进制地址。这是错误的,我想要文本。

    2) 为什么运营商<&书信电报;在临时std::ostringstream()上调用ostream操作符?临时文件的类型肯定是“ostringstream”而不是“ostream”?

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

    这似乎奏效了 并将“Value:5”传递给f()。


    我知道最好的选择是这样的:

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

    ……但我对在一条线上做这件事的行为感兴趣。假设有人想做一个(可疑的)宏:

    #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));
    

    这个功能会像预期的那样工作吗?

    5 回复  |  直到 16 年前
        1
  •  16
  •   Johannes Schaub - litb    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<< 是成员函数。这个 操作员<&书信电报; 那得花点时间 char const*

        2
  •  3
  •   Tronic    16 年前

    至于如何通过铸造来绕过这些限制,我有一种感觉,那就是它实际上是UB,但我不能肯定。其他人肯定会引用这个标准。

        3
  •  1
  •   Eliott    8 年前

    #include <iostream>
    #include <sstream>
    
    void f(const char * str)
    {
        std::cout << str << std::endl;
    }
    
    std::string str(void (*populate)(std::ostream &))
    {
        std::ostringstream stream;
        populate(stream);
        return stream.str();
    }
    
    int main(int argc, char * * args)
    {
        f(str([](std::ostream & ss){ ss << "Value: " << 5;  }).c_str());
        return 0;
    }
    
    // g++ -std=c++11 main.cpp -o main
    // ./main
    // Value: 5
    
        4
  •  0
  •   Tim Cooper    14 年前

    // 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));
    
        5
  •  0
  •   Michael Grazebrook    14 年前

    我用类似的东西来记录。

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

    输出:

    我的第一条信息

        6
  •  0
  •   Calmarius    6 年前

    从C++17开始,我们就有了模板的折叠表达式,可以用来生成通用的字符串格式化程序,它可以接受所有支持流的内容:

    template <class... Args>
    std::string format(Args &&... args)
    {
        std::ostringstream ostr;
    
        (ostr << ... << args);
    
        return ostr.str();
    }
    

    您可以像这样使用它: format("Int number: ", 42, " Float number: ", 3.14).c_str() .

    在C++20中 std::format