lmi
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [lmi] Stream cast problems with trailing spaces and more


From: Vadim Zeitlin
Subject: Re: [lmi] Stream cast problems with trailing spaces and more
Date: Thu, 30 Jan 2020 22:37:25 +0100

On Wed, 29 Jan 2020 23:02:34 +0000 Greg Chicares <address@hidden> wrote:

GC> On 2020-01-29 16:45, Greg Chicares wrote:
GC> [...]
GC> > something in the Standard that led me to believe that an infinity would
GC> > induce "Output failed" here:
GC> > 
GC> >     else if(!(interpreter >> result))
GC> >         {
GC> >         err << "Output failed ";
GC> >         }
GC> > 
GC> > because...well, I can't find the reason now, upon rereading the Standard.
GC> [...]
GC> > If you see better ways to induce these specific failures, please let me
GC> > know.
GC> In "INF", the characters 'I' and 'N'...
GC> 
GC>   https://cplusplus.github.io/LWG/lwg-active.html#2381
GC> | are correctly parsed by std::strtod, but not by the stream extraction 
operators
GC> 
GC> ...which could explain the outcome you report with clang and msvc,

 Yes, and to answer your question in the previous email, the "obvious"
explanation of the failure with clang for me was that its stream extraction
operators did support "INF" on input, unlike gcc/stdlibc++. And, indeed,
this can be seen by just compiling and running this example:
---------------------------------- >8 --------------------------------------
#include <iostream>

int main()
{
    double d = 0.0;
    std::cin >> d;
    std::cout << "State: " << std::cin.rdstate() << "\td=" << d << "\n";
}
---------------------------------- >8 --------------------------------------

with gcc and clang:

        % echo inf | ./stream.gcc
        State: 4        d=0
        % echo inf | ./stream.clang
        State: 0        d=inf

 For completeness, MSVC behaves like gcc, i.e. does _not_ support "INF":

        % echo inf | ./stream.msvc
        State: 2        d=0
 
so it also passes this test.

GC> if they haven't implemented the "proposed resolution".

 This is veering off-topic, but I'm not sure if the proposed resolution
changes anything concerning "inf". It seems to only address the hex
floating point numbers, i.e. it adds "p" and "P" to the list of accepted
characters, but not "i", or "n", nor "f".

GC> Instead of casting "INF" to double, how about casting "3" to bool?
GC> This amended test throws the expected exception with gcc-8.3:
GC> 
GC> diff --git a/stream_cast_test.cpp b/stream_cast_test.cpp
GC> index 08cea91c..cb03adc4 100644
GC> --- a/stream_cast_test.cpp
GC> +++ b/stream_cast_test.cpp
GC> @@ -79,7 +79,7 @@ int test_main(int, char*[])
GC>          );
GC>  
GC>      BOOST_TEST_THROW
GC> -        (stream_cast<double>("INF")
GC> +        (stream_cast<bool>("3")
GC>          ,std::runtime_error
GC>          ,lmi_test::what_regex("^Output failed")
GC>          );

 I can confirm that this also works, i.e. throws the expected exception,
with clang/libc++ and msvc.


 However it still leaves the other failure, which is the exception when
converting double to string in assay_speed(). The reason for it is also
clear now and is in the line

    else if(!(interpreter >> std::ws).eof())

As there is no whitespace to extract, this causes failbit to be set. eofbit
is set too, so the error here is not triggered, but the check for

    if(!interpreter || !interpreter.eof())

below is true because "!interpreter" is equivalent to checking for failbit
which is set. Again, this doesn't happen for gcc/libstdc++ because of a bug
in it, but it does happen for the other compilers.

 I don't know how would you prefer to fix this. My own preference would be
still what I did in https://github.com/vadz/lmi/pull/136, i.e. check for
eof() first, before extracting possible whitespace, but it's a bit uglier
now that we don't need a special error message for this case. But at least
this change:
---------------------------------- >8 --------------------------------------
diff --git a/stream_cast.hpp b/stream_cast.hpp
index 1a89d4d80..30cb5c6bd 100644
--- a/stream_cast.hpp
+++ b/stream_cast.hpp
@@ -123,7 +123,7 @@ To stream_cast(From from, To = To())
         {
         err << "Output failed ";
         }
-    else if(!(interpreter >> std::ws).eof())
+    else if(!interpreter.eof() && !(interpreter >> std::ws).eof())
         {
         err << "Unconverted data remains ";
         }
---------------------------------- >8 --------------------------------------
(in addition to the one replacing "INF" with "3" above) does allow the unit
test to pass when using all 3 compilers. If there is a more elegant way to
do it, without relying on stdlibc++ behaviour, I'm afraid I don't see it
right now.

 Regards,
VZ

Attachment: pgp4lVsBvR2vA.pgp
Description: PGP signature


reply via email to

[Prev in Thread] Current Thread [Next in Thread]