I've been thinking of using this:
template <typename T>
inline T from_string(const std::string& s){
std::istringstream iss;
iss.str(s);
T result;
iss >> result;
return result;
}
in my code. Then I thought "I shouldn't construct istringstreams all the time", and made it into this:
inline std::istringstream& get_istringstream(){
static thread_local std::istringstream stream;
stream.str("");
return stream;
}
template <typename T>
inline T from_string(const std::string& s){
auto& iss(get_istringstream());
iss.str(s);
T result;
iss >> result;
return result;
}
... and this builds and works (although I haven't tested it very extensively, nor ran performance tests). Would you say that "good enough" for general-purpose utility code, that is not intended to run in some tight loop? Are there other considerations I've overlooked, performance-wise (*) or usability-wise?
Perhaps I should mention my motivation here is partly how I found it strange that there's no std::from_string()
.
Edit: If you're concerned about the dependence on a default constructor, we can also throw in this:
template< typename T >
struct istream_traits {
inline static T read(std::istream& is)
{
T x;
is >> x;
return x;
}
};
template<> struct istream_traits<bool> {
inline static bool read(std::istream& is)
{
is >> std::boolalpha;
bool x;
is >> x;
return x;
}
};
template<typename T>
inline T read(std::istream& is)
{
T x = istream_traits<T>::read(is);
return x;
}
... and then replace T result; iss >> result;
with return read<T>(iss);
.
(*) - Yes, I know anything with iostreams is probably not fast to begin with.
string
, has specializations to speed it up for common types, and checks that the conversion was successful at the end (i.e., that the stream extraction exhausted the content of the stream). – Jerry Coffin Aug 26 '16 at 21:59