Search code examples
c++stlstreambytestream

Stream object that handles numbers


This may be a very basic question but while digging through STL reference I can't find anything suitable. As an example

std::ostringstream oss;
oss << "One hundred and one: " << 101;

would result in One hundred and one: 101 stored in oss, means the numeric value 101 is converted to text. What I'm looking for is a stream object that keeps the numeric value so that something like:

numstream nums;
nums << 10 << 0 << 15;

would result in a byte or string buffer containing not a textual representation of 10, 0 and 15 but just these three numbers.

Any idea what could be used for this?


Solution

  • A buffer containing a sequence of integers is what std::vector<int> controls.

    You can override the global operator << to append any type T to any container type C for which such an operation is meaningful:

    #include <vector>
    #include <iostream>
    
    std::vector<int> & operator<<(std::vector<int> & vi, int i)
    {
        vi.push_back(i);
        return vi;
    }
    
    int main()
    {
        std::vector<int> vi;
        vi << 1 << 2 << 3;
        for(auto i : vi) {
            std::cout << i << std::endl;
        }
        return 0;
    }
    

    However, if all you want to achieve is an abbreviation of, e.g.

    si.push_back(i);
    

    for some integer sequence si and int i, and to be able to shorten, e.g.

    si.push_back(i);
    si.push_back(j);
    si.push_back(k);
    

    to:

    si << i << j << k;
    

    remember that the brevity you gain comes at the cost of making otherwise skilled readers research what your abbreviations are - and how safe they are.

    I suggest that shortening si.push_back(i) to si << i is not worthwhile and that if you want to get tiresomely long sequences of push_back(n) onto one line then it would be sufficient and less eccentric to define a type-safe variadic function template for the purpose, e.g.

    void push_back(std::vector<int> & vi){}
    
    template<typename ...Ts>
    void push_back(std::vector<int> & vi, int i, Ts... ts)
    {
        vi.push_back(i);
        if (sizeof...(Ts)) {
            push_back(vi,ts...);
        }
    }
    

    With which you would write, e.g.

    push_back(si,i,j,k);
    

    rather than:

    si << i << j << k;