See boost::lexical_cast
. Basically, you need to specialize
for the cases where >>
doesn't do what you want. If you want
string_to_T<std::string>
to be a no-op, for example, you write
a specialization:
template<>
std::string
string_to_T<std::string>( std::string const& s )
{
return s;
}
For more complicated cases, you can forward to a functional
object, and use partial specialization, but for the case you
describe, this shouldn't be necessary.
While you're at it, you should probably think about error
handling. What happens if you call string_to_T<int>
, and the
input is "abcd"? For that matter, if you call
string_to_T<int>
with "1 2 3 4"
, should the results be 1, or
an error?
EDIT:
Having seen more of the comments to your question: you cannot
change the return type at runtime (with certain very limited
exceptions when returning a reference or a pointer within a
class hierarchy). C++ is a statically typed language, every
expression has a distinct type, determined at compile time.
Supposing you could return two different types, how would you
use the function, and how could the compiler detect the type
errors it is required to detecte. The closest you can come is
to return some sort of proxy, with implicit conversions to the
various types, but the type you convert to would still be
statically determined, according to what you do with the
results: assign it to an int
, and it will convert to an int
,
regardless of the contents of the string.
This type safety is a feature; detecting errors at compile time
makes the code far more robust and sure than deferring the error
detection to runtime. If you can do without this safety
(non-critical application), and need the added flexibility of
runtime typing, C++ is not the right language; you should be
using something like Python.
EDIT 2:
In response to your comment, the solution would seem to be
something along the lines of:
class ToStringHelper
{
std::string myValue;
public:
ToStringHelper( std::string const& value )
: myValue( value )
{
}
operator std::string() const
{
return myValue;
}
template <typename T>
operator T() const
{
std::istringstream cvt( myValue );
T results;
cvt >> results;
// Error checking here...
return results;
}
};
ToStringHelper
string_to_T( std::string const& s )
{
return ToStringHelper( s );
}
I use this exact pattern for configuration data (with errors
triggering an exception).