1

Simple utility function to convert a value to std::string while keeping backwards compatibility.
Probably a silly question, but I'm curious to hear some opinions about it or if there are any flaws in doing so this way:

     template<typename T>
     std::string toString(T parm)
     {
#ifdef CXX11_AVAILABLE
         return std::to_string(parm);
#else
         std::ostringstream stream;
         stream << parm;

         return stream.str();
#endif
     }

Will it create a copy in memory if I do it like that?
Thanks in advance for your answers :)

  • 1
    yes, until c++17 `ostringstream::str()` returns a copy of the underlying string. As of c++17 `str()` has an r-value form. – Richard Hodges May 14 '18 at 09:13
  • @RichardHodges Thank you! DevSolar Thank you for the reference, but to be honest, I already saw that post and it wasn't very specific about backwards compatibility. Could you please explain why would __cplusplus definition checks for C++11? –  May 14 '18 at 09:29
  • 5
    Your template accepts all sorts of T but `std::to_string()` won't be able to convert `char[]` or `const char *` while `std::ostringstream` will. – Killzone Kid May 14 '18 at 09:32
  • 1
    @RichardHodges: That's not C++17; that's C++20. And it will have a different function, not an r-value overload. – Nicol Bolas May 14 '18 at 19:12
  • 1
    @RichardHodges `ostringstream::str()` is a prvalue (as is any call of a function that returns by value). I guess you refer to some future function that will move the underlying string out of an ostringstream; there is no such thing in C++17 – M.M May 14 '18 at 21:23

1 Answers1

1

A few points:

First, instead of #ifdef CXX11_AVAILABLE you want to check if __cplusplus > 201103L; for an explanation, see:

http://stackoverflow.com/questions/11053960/ddg#11054055

Now, you're going to have at least one copy anyway, just by piping the string into the ostringstream, regardless of which C++ version you're using.

Also, you're going to be creating and destroying an ostringstream with every damn call to toString() - that's terrible! ... at least do:

namespace detail {
inline std::ostringstream& get_ostringstream(){
        static thread_local std::ostringstream stream;
        stream.str("");
        stream.clear();
        return stream;
}
} // namespace detail

and then in toString(), replace

std::ostringstream oss;

with

std::ostringstream& oss = detail::get_ostringstream();

Finally, remember that the final copy - the oss.str() is subject to Return Value Optimization (RVO), which in C++17 is mandatory and for earlier standard was applied by most compilers. So if you initialize a string with the result of the function, the construction of the oss.str() copy would take place at the address of that outside string.

Edit: Actually, if this is performance-critical code, you should just not be using general-purpose string conversion functions, and possibly not use std::string at all. Of course - before customizing anything, profile and check where you're hurting performance-wise.

einpoklum
  • 118,144
  • 57
  • 340
  • 684
  • Thank you for the great clarification! That's the kind of answer I've been looking for :) P.S: I forgot to mention that CXX11_AVAILABLE is just a define for __cplusplus > 201103L. –  May 14 '18 at 19:52