I interpreted this the opposite way: that the library's attempt
to match "Infinity" would fail at 'x' and therefore push back 'x'
and return 0, having consumed "Infinit".
This is the point where I'm not sure. From the above phrase, it
seems clear that the "%f" specifier would consume "Infinit".
The question is then whether this sequence is an error. There
is a statement (§7.19.6.2/10): "If the input item is not a
matching sequence, the execution of the directive fails: this
condition is a matching failure." But what does it really mean
by "matching sequence"; for "%f", all it says is: "Matches an
optionally signed floating-point number, infinity, or NaN whose
format is the same as expected for the subject sequence of the
strtod function." The strtod function accepts "Infinit" without
problems.
But you're probably right, since in the description of stdtod,
the term "subject sequence" is also used, and given "Infinit" as
input, the "subject sequence" for stdtod is "Inf", which is not
the sequence which was extracted.
This would solve Jim Langston's problem nicely. In his
conversion operator, having gotten past any leading white space
and the sign, he can then do a switch on the next character:
[0-9.], and the usual floating point conversion can be used
(he's already extracted the sign, but that's easy to handle
after the conversion); [Ii], and he advances, extracting the
characters, trying to match "infinity"---if the resulting string
matches "inf" or "infinity", that's the results, otherwise, it's
an error; and for [Nn], he does the same thing for "nan" (not
forgetting the n-char-sequence, if he wants to be strictly
conform with C---but then, he also has to handle the hex
format, since his C++ implementation almost certainly won't).
Just for the fun of it, I whipped up a simple implementation
here. It doesn't handle all of the formatting flags correctly,
and it supposes a C99 compliant math.h, but it should be a good
starting point:
class FloatWithInfIn
{
public:
FloatWithInfIn( float& f )
: myValue( &f )
{
}
friend std:

stream&operator<<( std:

stream& dest,
FloatWithInfIn const& src ) ;
friend std::istream&operator>>( std::istream& source,
FloatWithInfIn const& dest ) ;
private:
float* myValue ;
} ;
class FloatWithInfOut
{
public:
FloatWithInfOut( float const& f )
: myValue( &f )
{
}
friend std:

stream&operator<<( std:

stream& dest,
FloatWithInfOut const& src ) ;
private:
float const* myValue ;
} ;
std:

stream&
outputFloatWithInf(
std:

stream& dest,
float const& value )
{
switch ( fpclassify( value ) ) {
case FP_INFINITE :
if ( value < 0.0 ) {
dest << '-' ;
} else if ( (dest.flags() & std::ios::showpos) != 0 ) {
dest << '+' ;
}
dest << "Infinity" ;
break ;
case FP_NAN :
dest << "NaN" ;
break ;
default :
dest << value ;
break ;
}
return dest ;
}
inline std:

stream&
operator<<(
std:

stream& dest,
FloatWithInfOut const&
value )
{
return outputFloatWithInf( dest, *value.myValue ) ;
}
inline std:

stream&
operator<<(
std:

stream& dest,
FloatWithInfIn const&
value )
{
return outputFloatWithInf( dest, *value.myValue ) ;
}
void
getInfinity(
std::istream& source,
float& dest )
{
static std::string const
inf( "infinity" ) ;
std::ctype< char > const&
ctype
= std::use_facet said:
std::string extracted ;
std::string::const_iterator
pos = inf.begin() ;
while ( pos != inf.end() && ctype.tolower( source.peek() ) ==
*pos ) {
extracted += ctype.tolower( source.get() ) ;
++ pos ;
}
if ( extracted != "inf" && extracted != "infinity" ) {
source.setstate( std::ios::failbit ) ;
} else {
dest = std::numeric_limits< float >::infinity() ;
}
}
void
getNaN(
std::istream& source,
float& dest )
{
static std::string const
nan( "nan" ) ;
std::ctype< char > const&
ctype
= std::use_facet said:
std::string extracted ;
std::string::const_iterator
pos = nan.begin() ;
while ( pos != nan.end() && ctype.tolower( source.peek() ) ==
*pos ) {
extracted += ctype.tolower( source.get() ) ;
++ pos ;
}
if ( extracted != "nan" ) {
source.setstate( std::ios::failbit ) ;
} else {
// Or maybe only characters in the basic character set
// should be allowed here.
while ( ctype.is( std::ctype_base::alnum, source.peek() )
|| source.peek() == '_' ) {
source.get() ;
}
dest = std::numeric_limits< float >::quiet_NaN() ;
}
}
std::istream&
operator>>(
std::istream& source,
FloatWithInfIn const&
dest )
{
if ( (source.flags() & std::ios::skipws) != 0 ) {
source >> std::ws ;
}
char sign
= ( source.peek() == '-' || source.peek() == '+'
? source.get()
: '+' ) ;
float result = 0.0 ;
switch ( source.peek() ) {
case 'I' :
case 'i' :
getInfinity( source, result ) ;
break ;
case 'N' :
case 'n' :
getNaN( source, result ) ;
break ;
default :
{
// Should use RAII for this, since >> can throw...
std::ios::fmtflags flags = source.flags() ;
source.unsetf( std::ios::skipws ) ;
source >> result ;
source.flags( flags ) ;
}
break ;
}
if ( source ) {
*dest.myValue = ( sign == '-'
? - result
: result ) ;
}
return source ;
}
FloatWithInfIn
floatWithInf(
float& f )
{
return FloatWithInfIn( f ) ;
}
FloatWithInfOut
floatWithInf(
float const& f )
{
return FloatWithInfOut( f ) ;
}
(Note the use of a function to automatically choose, according
to lvalue-ness and const-ness, whether we can do just output, or
both.)