2016-08-03 63 views
18

由于一些类型的可流:Stream对象直接进入的std :: string

struct X { 
    int i; 

    friend std::ostream& operator<<(std::ostream& os, X const& x) { 
     return os << "X(" << x.i << ')'; 
    } 
}; 

我想这追加到std::string。我可以为实现这个:

void append(std::string& s, X const& x) { 
    std::ostringstream os; 
    os << x; 
    s.append(os.str()); 
} 

但是,这因为我写数据到一个流只是然后分配一个新的字符串只是其附加到一个不同的目的似乎跛。有更直接的路线吗?

+0

我想看看http://www.boost.org/doc/libs/1_61_0/doc/html/interprocess/streams.html – bobah

+0

可能实现'std :: string X :: repr()'或类似的,并在'append'和'operator <<'中调用?不理想,但您避免使用中间'stringstream'。 – Praetorian

+0

简单地说's.append(std :: string :: to_string(x));'?我错过了一些重要的东西吗 –

回答

13

这可以通过一种新型的streambuf来解决(参见Standard C++ IOStreams and Locales: Advanced Programmer's Guide and Reference)。

这里是它如何可以看看草图:

#include <streambuf> 

class existing_string_buf : public std::streambuf 
{ 
public: 
    // Store a pointer to to_append. 
    explicit existing_string_buf(std::string &to_append); 

    virtual int_type overflow (int_type c) { 
     // Push here to the string to_append. 
    } 
}; 

一旦你在这里充实的细节,你可以按如下方式使用它:

#include <iostream> 

std::string s; 
// Create a streambuf of the string s 
existing_string_buf b(s); 
// Create an ostream with the streambuf 
std::ostream o(&b); 

现在,你只写o,结果应显示为附加到s

// This will append to s 
o << 22; 

编辑

由于@rustyx正确地指出,覆盖xsputn需要提高性能。

完整的例子

下打印22

#include <streambuf> 
#include <string> 
#include <ostream> 
#include <iostream> 

class existing_string_buf : public std::streambuf 
{ 
public: 
    // Somehow store a pointer to to_append. 
    explicit existing_string_buf(std::string &to_append) : 
     m_to_append(&to_append){} 

    virtual int_type overflow (int_type c) { 
     if (c != EOF) { 
      m_to_append->push_back(c); 
     } 
     return c; 
    } 

    virtual std::streamsize xsputn (const char* s, std::streamsize n) { 
     m_to_append->insert(m_to_append->end(), s, s + n);                     
     return n; 
    } 

private: 
    std::string *m_to_append; 
}; 


int main() 
{ 
    std::string s; 
    existing_string_buf b(s); 
    std::ostream o(&b); 

    o << 22; 

    std::cout << s << std::endl; 
} 
+2

我也会重写'xsputn()'以获得良好的性能。 – rustyx

+0

@rustyx优秀的一点。添加。非常感谢 –

+4

有些时候,我觉得我知道C++。这不是其中之一。 – Barry

1

你可以写一个的std :: string转换操作符:

struct X { 
int i; 

friend std::ostream& operator<<(std::ostream& os, X const& x) { 
    os << "X(" << x.i << ')'; 
    return os; 
} 

operator std::string() { 
    return std::string("X(") + std::to_string(x.i) + ")"; 
} 

}; 

然后,你可以简单地把它添加到std :: string:

X myX; 
myX.i = 2; 
std::string s("The value is "); 
s.append(myX); //myX is cast into the string "X(2)" 
+0

好的,但现在我有两次相同的逻辑。 – Barry

+0

是的。将运算符<<方法的第一行更改为“os << static_cast (x);”。 – HeywoodFloyd

-1

由于原始字符串对于现有分配可能只有足够大的空间,所以您可以希望的最好方法是将所有要添加到流中的所有内容格式化,然后像在示例中那样附加结果。

如果您打算经常执行这些附加操作,我会认为std :: string是手头问题的错误类型。我建议直接使用std :: ostringtream而不是std :: string,并且只在需要最终结果时才转换为字符串。

1

在这种特定的情况下,我只是遵循KISS原则:

struct X { 
    int i; 

    std::string toString() const { 
     return "X(" + std::to_string(i) + ")"; 
    } 
}; 

用法:

string += x.toString(); 
std::cout << x.toString(); 

operator<<(std::ostream&, …)是不是真的适合一般串转换,因此,如果这就是你'之后再使用toString类型的方法/自由函数要好得多。如果你想std::cout << x,你可以简单地实施operator<<只需拨打toString