0
votes

I wrote the following utility C++ class.

/*!
 * \brief The \b StringBuilder class is used for efficiently constructing long
 * strings out of many small ones. Internally it uses \b std::ostringstream and
 * its advantage compared to usage of raw \b std::ostringstream is that it is
 * capable to be used on single line and implicitly converted to \b std::string
 * everywhere this type is expected.
 * \code{.cpp}
 * void foo(const std::string& s);
 * foo(utils::StringBuilder("The answer is: ") << 42 << std::endl);
 * \endcode
 */
class StringBuilder
{
public:
    StringBuilder() = default;

    template <class... Args>
    explicit StringBuilder(Args&&... args)
    {
        append(std::forward<Args>(args)...);
    }

    template <class T>
    StringBuilder& append(const T& arg)
    {
        _data << arg;
        return *this;
    }

    template <class T, class... Args>
    StringBuilder& append(const T& arg, Args&&... args)
    {
        _data << arg;
        append(std::forward<Args>(args)...);
        return *this;
    }

    std::string toString() const
    {
        return _data.str();
    }

    operator std::string() const
    {
        return toString();
    }

    template <class T>
    StringBuilder& operator<<(const T& object)
    {
         return append(object);
    }

private:
    std::ostringstream _data;
};

cannot compile. The error message is quite long to paste here, but it start with:

main.cpp: In function ‘int main()’: main.cpp:37:8: error: no match for ‘operator<<’ (operand types are ‘utils::StringBuilder’ and ‘’) sb << endl;

and ends with:

/usr/include/c++/4.8.3/bits/basic_string.h:2753:5: note: template argument deduction/substitution failed: main.cpp:36:33: note:
‘utils::StringBuilder’ is not derived from ‘std::basic_ostream<_CharT, _Traits>’ cout << (StringBuilder() << endl);

How to make StringBuilder to be able to accept std::endl and other IO manipulators?

1
Doesn't std::ostringstream already do this? What's your actual need to roll your own?πάντα ῥεῖ
I'm described the need in the comment above.bobeff

1 Answers

2
votes

endl (as well as the iomanip operands) is a function.

Just write an overload like this

StringBuilder& operator<<(ostream& func(ostream&))
{
    _data << func;
    return *this;
}

.. or as an external operator like this

StringBuilder& operator<<(StringBuilder& sb, ostream& func(ostream&)) ...

...and it will work for all of them