2016-08-03 6 views
18

Biorąc pod uwagę, że jest jakiś rodzaj przesyłania strumieniowego:Stream obiekt bezpośrednio do std :: string

struct X { 
    int i; 

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

chcę dołączyć to wychodzą na std::string. Mogę realizować to jako:

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

Ale to wydaje chromy ponieważ piszę do jednego strumienia danych tylko wtedy przydzielić nowy ciąg tylko dla celów dołączając ją na inną. Czy istnieje bardziej bezpośrednia trasa?

+0

Zajrzałbym w stronę http://www.boost.org/doc/libs/1_61_0/doc/html/interprocess/streams.html – bobah

+0

Może zaimplementować 'std :: string X :: repr()' lub podobny i wywołać to zarówno w 'append' i' operator << '? Nie jest idealny, ale unikasz pośredniego "ciągu". – Praetorian

+0

A może po prostu 's.append (std :: string :: to_string (x));'? Czy tęskniłem za czymś niezbędnym? –

Odpowiedz

13

Można to rozwiązać przez nowy typ streambuf (patrz Standard C++ IOStreams and Locales: Advanced Programmer's Guide and Reference).

Oto szkic jak to może wyglądać:

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

Po ukształtowaniu szczegóły tutaj, można go używać w następujący sposób:

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

Teraz wystarczy napisać do o, a wynik powinien pojawić się jako dołączony do s.

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

Edit

Jak @rustyx prawidłowo zauważa, nadrzędnymi xsputn jest wymagane dla poprawy wydajności.

Pełna Przykład

następujące wydruki 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

Nadmiernie zastąpiłbym 'xsputn()' dla dobrej wydajności. – rustyx

+0

@rustyx Doskonały punkt. Dodany. Wielkie dzięki –

+4

Są chwile, kiedy czuję, że znam C++. To nie jest jeden z tych czasów. – Barry

1

można napisać operatora odlewania 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) + ")"; 
} 

}; 

Następnie można po prostu dołączyć go do 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

Ok, ale teraz mam tę samą logikę dwa razy. – Barry

+0

Prawda. Zmień pierwszą linię operatora << method na "os << static_cast (x);". – HeywoodFloyd

-1

Ponieważ oryginalny ciąg jest prawdopodobnie wystarczająco duży dla istniejącej alokacji, najlepiej jest sformatować wszystko, co chcesz dodać raz w strumieniu, a następnie dołączyć wynik, jak w przykładzie.

Jeśli masz zamiar wykonywać te dodatki często, twierdzę, że std :: string jest nieprawidłowym typem problemu. Polecam używanie std :: ostringtream bezpośrednio zamiast std :: string, i tylko konwertuję na ciąg, kiedy potrzebujesz końcowego wyniku.

1

W tym konkretnym przypadku, chcę tylko być zgodne z zasadą KISS:

struct X { 
    int i; 

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

Zastosowanie:

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

operator<<(std::ostream&, …) jest naprawdę nie nadaje się do rodzajowego konwersji strun, więc jeśli o to ci po tym przypadku metoda/funkcja wolna jest znacznie lepsza.A jeśli chcesz std::cout << x, możesz łatwo wdrożyć operator<<, aby zadzwonić pod numer toString.