Am Mittwoch, 13. September 2006 22:37 schrieb Angus Leeming: > Georg Baum <[EMAIL PROTECTED]> writes: > > Try this one. On linux the output is: > > > > global has std::codecvt<boost::uint32_t> facet: 0 > > global has std::ctype<boost::uint32_t> facet: 0 > > global has std::num_put<boost::uint32_t> facet: 0 > > terminate called after throwing an instance of 'std::bad_cast' > > what(): St8bad_cast > > Hmmmm. So it throws when filling the basic_ostringstream<boost::uint32_t>?
Yes. Because of missing ctype: #0 0xffffe410 in __kernel_vsyscall () #1 0xa7d15821 in raise () from /lib/tls/i686/cmov/libc.so.6 #2 0xa7d16fb9 in abort () from /lib/tls/i686/cmov/libc.so.6 #3 0xa7f04aa4 in __gnu_cxx::__verbose_terminate_handler () from /usr/lib/libstdc++.so.6 #4 0xa7f024c5 in std::set_unexpected () from /usr/lib/libstdc++.so.6 #5 0xa7f02502 in std::terminate () from /usr/lib/libstdc++.so.6 #6 0xa7f0263a in __cxa_throw () from /usr/lib/libstdc++.so.6 #7 0xa7e96b25 in std::__throw_bad_cast () from /usr/lib/libstdc++.so.6 #8 0x0804cd15 in std::__check_facet<std::ctype<unsigned int> > (__f=0x0) at /usr/lib/gcc/i486-linux-gnu/4.1.2/../../../../include/c++/4.1.2/bits/localefwd.h:187 #9 0x0804cd3c in std::basic_ios<unsigned int, std::char_traits<unsigned int> >::widen (this=0xafbc1848, __c=120 'x') at /usr/lib/gcc/i486-linux-gnu/4.1.2/../../../../include/c++/4.1.2/bits/basic_ios.tcc:122 #10 0x0804d48c in std::operator<< <unsigned int, std::char_traits<unsigned int> > ([EMAIL PROTECTED], __c=120 'x') at /usr/lib/gcc/i486-linux-gnu/4.1.2/../../../../include/c++/4.1.2/ostream:429 #11 0x08049168 in main () at locale-test.cpp:16 The attached version prints this: global has std::codecvt<boost::uint32_t> facet: 0 global has std::ctype<boost::uint32_t> facet: 0 global has std::num_put<boost::uint32_t> facet: 0 newlocale has std::codecvt<boost::uint32_t> facet: 0 newlocale has std::ctype<boost::uint32_t> facet: 1 newlocale has std::num_put<boost::uint32_t> facet: 0 stringstream test: It does still not work, this time because of num_put (it does not throw, because the exception is caught in operator<<. > Incidentally, I don't think that you mean this: > std::cerr << "global has std::num_put<boost::uint32_t> facet: " > << std::has_facet<std::ctype<boost::uint32_t> >(global) > << std::endl; Well spotted, thanks. Enrico, please use the attached version for testing. Georg
#include <boost/cstdint.hpp> #include <iostream> #include <locale> #include <sstream> #ifdef __GNUC__ namespace std { template<> ctype<boost::uint32_t>::~ctype() {} template<> bool ctype<boost::uint32_t>::do_is(ctype<boost::uint32_t>::mask, boost::uint32_t) const { return false; } template<> boost::uint32_t const * ctype<boost::uint32_t>::do_is(const boost::uint32_t *, const boost::uint32_t *, ctype<boost::uint32_t>::mask *) const { return 0; } template<> const boost::uint32_t * ctype<boost::uint32_t>::do_scan_is(ctype<boost::uint32_t>::mask, const boost::uint32_t *, const boost::uint32_t *) const { return 0; } template<> const boost::uint32_t * ctype<boost::uint32_t>::do_scan_not(ctype<boost::uint32_t>::mask, const boost::uint32_t *, const boost::uint32_t *) const { return 0; } template<> boost::uint32_t ctype<boost::uint32_t>::do_toupper(boost::uint32_t) const { return 0; } template<> const boost::uint32_t * ctype<boost::uint32_t>::do_toupper(boost::uint32_t *, boost::uint32_t const *) const { return 0; } template<> boost::uint32_t ctype<boost::uint32_t>::do_tolower(boost::uint32_t) const { return 0; } template<> const boost::uint32_t * ctype<boost::uint32_t>::do_tolower(boost::uint32_t *, boost::uint32_t const *) const { return 0; } template<> boost::uint32_t ctype<boost::uint32_t>::do_widen(char) const { return 0; } template<> const char * ctype<boost::uint32_t>::do_widen(const char *, const char *, boost::uint32_t *) const { return 0; } template<> char ctype<boost::uint32_t>::do_narrow(const boost::uint32_t, char) const { return 0; } template<> const boost::uint32_t * ctype<boost::uint32_t>::do_narrow(const boost::uint32_t *, const boost::uint32_t *, char, char *) const { return 0; } } #endif class ascii_ctype_facet : public std::ctype<boost::uint32_t> { public: typedef boost::uint32_t char_type; typedef wctype_t wmask_type; explicit ascii_ctype_facet(size_t refs = 0) : std::ctype<char_type>(refs) { _M_initialize_ctype(); } protected: bool M_narrow_ok; char M_narrow[128]; wint_t M_widen[1 + static_cast<unsigned char>(-1)]; mask M_bit[16]; wmask_type M_wmask[16]; wmask_type M_convert_to_wmask(const mask m) const { wmask_type ret; switch (m) { case space: ret = wctype("space"); break; case print: ret = wctype("print"); break; case cntrl: ret = wctype("cntrl"); break; case upper: ret = wctype("upper"); break; case lower: ret = wctype("lower"); break; case alpha: ret = wctype("alpha"); break; case digit: ret = wctype("digit"); break; case punct: ret = wctype("punct"); break; case xdigit: ret = wctype("xdigit"); break; case alnum: ret = wctype("alnum"); break; case graph: ret = wctype("graph"); break; default: ret = wmask_type(); } return ret; } void _M_initialize_ctype() { wint_t i; for (i = 0; i < 128; ++i) { const int c = wctob(i); if (c == EOF) break; else M_narrow[i] = static_cast<char>(c); } if (i == 128) M_narrow_ok = true; else M_narrow_ok = false; for (size_t i = 0; i < sizeof(M_widen) / sizeof(wint_t); ++i) M_widen[i] = btowc(i); for (size_t i = 0; i <= 15; ++i) { M_bit[i] = static_cast<mask>(1 << i); M_wmask[i] = M_convert_to_wmask(M_bit[i]); } } virtual ~ascii_ctype_facet() {} char_type do_toupper(char_type c) const { return towupper(c); } char_type const * do_toupper(char_type * lo, char_type const * hi) const { while (lo < hi) { *lo = towupper(*lo); ++lo; } return hi; } char_type do_tolower(char_type c) const { return towlower(c); } char_type const * do_tolower(char_type * lo, char_type const * hi) const { while (lo < hi) { *lo = towlower(*lo); ++lo; } return hi; } bool do_is(mask m, char_type c) const { bool ret = false; // Generically, 15 (instead of 10) since we don't know the numerical // encoding of the various categories in /usr/include/ctype.h. const size_t bitmasksize = 15; for (size_t bitcur = 0; bitcur <= bitmasksize; ++bitcur) if (m & M_bit[bitcur] && iswctype(c, M_wmask[bitcur])) { ret = true; break; } return ret; } char_type const * do_is(char_type const * lo, char_type const * hi, mask * vec) const { for (;lo < hi; ++vec, ++lo) { // Generically, 15 (instead of 10) since we don't know the numerical // encoding of the various categories in /usr/include/ctype.h. const size_t bitmasksize = 15; mask m = 0; for (size_t bitcur = 0; bitcur <= bitmasksize; ++bitcur) if (iswctype(*lo, M_wmask[bitcur])) m |= M_bit[bitcur]; *vec = m; } return hi; } char_type const * do_scan_is(mask m, char_type const * lo, char_type const * hi) const { while (lo < hi && !this->do_is(m, *lo)) ++lo; return lo; } char_type const * do_scan_not(mask m, char_type const * lo, char_type const * hi) const { while (lo < hi && this->do_is(m, *lo) != 0) ++lo; return lo; } virtual char_type do_widen(char c) const { if (static_cast<unsigned char>(c) < 128) return c; throw std::bad_cast(); } virtual const char* do_widen(const char* lo, const char* hi, char_type* dest) const { while (lo < hi) { if (static_cast<unsigned char>(*lo) >= 128) throw std::bad_cast(); *dest = *lo; ++lo; ++dest; } return hi; } virtual char do_narrow(char_type wc, char) const { if (wc < 128) return static_cast<char>(wc); throw std::bad_cast(); } virtual const char_type * do_narrow(const char_type * lo, const char_type * hi, char, char * dest) const { while (lo < hi) { if (*lo < 128) *dest = static_cast<char>(*lo); else throw std::bad_cast(); ++lo; ++dest; } return hi; } }; void testlocale(char const * const name, std::locale const & l) { std::cerr << name << " has std::codecvt<boost::uint32_t> facet: " << std::has_facet<std::codecvt<boost::uint32_t, char, std::mbstate_t> >(l) << std::endl; std::cerr << name << " has std::ctype<boost::uint32_t> facet: " << std::has_facet<std::ctype<boost::uint32_t> >(l) << std::endl; std::cerr << name << " has std::num_put<boost::uint32_t> facet: " << std::has_facet<std::num_put<boost::uint32_t> >(l) << std::endl; } int main() { std::locale const global; testlocale("global", global); std::locale const newlocale(global, new ascii_ctype_facet); testlocale("newlocale", newlocale); std::locale::global(newlocale); std::basic_ostringstream<boost::uint32_t> os; os << 'x' << 11 << ' ' << 3.0; std::basic_string<boost::uint32_t> const s(os.str()); std::cerr << "stringstream test: "; for (size_t i = 0; i < s.size(); ++i) std::cerr << s[i]; std::cerr << '\n'; return 0; }