c++ - How to have all platform compiler output the same string for NaN? -
consider code snippet:
#include <iostream> #include <string> #include <limits> int main() { std::cout << std::numeric_limits<double>::quiet_nan(); }
when compiled visual studio 2010, output 1.#qnan
. when compiled g++, output nan
. note visual studio 2015 outputs "nan".
however, need both produce same output. what's simple way that? tried override operator<<
double
feel that's not right way do. can string used nan
value forced @ stream
level, or better, @ global level (using std::locale
stuff?...never used that...).
i found squaring_num_put example. interesting because it's way modify number redirected output. i'm having hard time trying adapt problem (could not make do_put
send either number or hard coded "nan" string ostream
...).
you might use stream manipulator or modify underlying locale:
manipulator:
#include <cmath> #include <ostream> template <typename t> struct floatformat { const t value; floatformat(const t& value) : value(value) {} void write(std::ostream& stream) const { if(std::isnan(value)) stream << "not number"; else stream << value; } }; template <typename t> inline floatformat<t> float_format(const t& value) { return floatformat<t>(value); } template <typename t> inline std::ostream& operator << (std::ostream& stream, const floatformat<t>& value) { value.write(stream); return stream; } int main() { std::cout << float_format(std::numeric_limits<double>::quiet_nan()) << '\n'; }
locale:
#include <cmath> #include <locale> #include <ostream> template<typename iterator = std::ostreambuf_iterator<char>> class numput : public std::num_put<char, iterator> { private: using base_type = std::num_put<char, iterator>; public: using char_type = typename base_type::char_type; using iter_type = typename base_type::iter_type; numput(std::size_t refs = 0) : base_type(refs) {} protected: virtual iter_type do_put(iter_type out, std::ios_base& str, char_type fill, double v) const override { if(std::isnan(v)) out = std::copy(std::begin(notanumber), std::end(notanumber), out); else out = base_type::do_put(out, str, fill, v); return out; } virtual iter_type do_put(iter_type out, std::ios_base& str, char_type fill, long double v) const override { if(std::isnan(v)) out = std::copy(std::begin(notanumber), std::end(notanumber), out); else out = base_type::do_put(out, str, fill, v); return out; } private: static const char notanumber[]; }; template<typename iterator> const char numput<iterator>::notanumber[] = "not number"; #include <iostream> #include <limits> int main() { #if 1 { const std::size_t nodestroy = 1; numput<> num_put(nodestroy); std::locale locale(std::cout.getloc(), &num_put); std::locale restore_locale = std::cin.getloc(); std::cout.imbue(locale); std::cout << std::numeric_limits<double>::quiet_nan() << '\n'; // num_put facet going out of scope: std::cout.imbue(restore_locale); } #else { // alternitvely use reference counted facet , pass ownership locales: auto num_put = new numput<>(); std::locale locale(std::cout.getloc(), num_put); std::cout.imbue(locale); std::cout << std::numeric_limits<double>::quiet_nan() << '\n'; } #endif std::cout << std::numeric_limits<double>::quiet_nan() << '\n'; }
Comments
Post a Comment