2013-10-06 5 views
11

Therearealready Stackoverflow पर questions यहाँ पूछ क्योंbasic_fstream<uint8_t> काम नहीं करता। उत्तरों का कहना है कि char_traits केवल char और wchar_t (char16_t, char32_t सी ++ में) के लिए विशिष्ट है और आपको basic_fstream<char> के साथ बाइनरी डेटा पढ़ने और आवश्यक होने पर इसे कास्ट करने के लिए चिपकना चाहिए।यह विशिष्ट char_traits <uint8_t> और codecvt <uint8_t> क्यों बुनियादी_ifstream टेम्पलेट के साथ उपयोग के लिए std :: bad_cast फेंक देता है?

अच्छी तरह से इसे कम करें, यह पर्याप्त नहीं है! :) जवाब (है कि मैं पा सकते हैं) की

कोई भी कहते हैं कि कैसेchar_traits<uint8_t> विशेषज्ञ और एक basic_fstream टेम्पलेट के साथ इसका इस्तेमाल, या अगर यह भी संभव है करने के लिए। तो मैंने सोचा कि मैं इसे स्वयं लागू करने की कोशिश करूंगा।

विंडोज 7 64 बिट पर विजुअल स्टूडियो एक्सप्रेस 2013 आरसी और कुबंटू जीएनयू/लिनक्स 13.04 64 बिट पर जी ++ - 4.7 के साथ त्रुटि के बिना निम्नलिखित संकलन। हालांकि यह रनटाइम पर std :: bad_cast अपवाद फेंकता है। उस संयोजन का परीक्षण करने के लिए मुझे libC++ के साथ clang ++ तक पहुंच नहीं है।

#include <cinttypes> 
#include <cstring> 

#include <algorithm> 
#include <fstream> 
#include <iostream> 
#include <locale> 

#ifdef _WIN32 
    #define constexpr 
    #define NOEXCEPT throw() 
#else 
    #define NOEXCEPT noexcept 
#endif 

// Change this to char and it works. 
using byte_type = std::uint8_t; 

namespace std 
{ 
    // Specialization of std::char_traits 
    template <> struct char_traits<std::uint8_t> 
    { 
     using char_type = std::uint8_t; 
     using int_type = int; 
     using off_type = std::streamoff; 
     using pos_type = std::streampos; 
     using state_type = std::mbstate_t; 

     static void assign(char_type& value1, const char_type& value2) 
     { 
      value1 = value2; 
     } 

     static char_type* assign(char_type* ptr, std::size_t count, char_type value) 
     { 
      return static_cast<char_type*>(std::memset(ptr, value, count)); 
     } 

     static constexpr bool eq(const char_type& value1, const char_type& value2) NOEXCEPT 
     { 
      return value1 == value2; 
     } 

     static constexpr bool lt(const char_type value1, const char_type value2) NOEXCEPT 
     { 
      return value1 < value2; 
     } 

     static std::size_t length(const char_type* ptr) 
     { 
      std::size_t i = 0; 
      while (!eq(ptr[i], char_type())) 
      { 
       ++i; 
      } 
      return i; 
     } 

     static int compare(const char_type* ptr1, const char_type* ptr2, std::size_t count) 
     { 
      return std::memcmp(ptr1, ptr2, count); 
     } 

     static const char_type* find(const char_type* ptr, std::size_t count, const char_type& value) 
     { 
      return static_cast<const char_type*>(std::memchr(ptr, value, count)); 
     } 

     static char_type* move(char_type* dest, const char_type* src, std::size_t count) 
     { 
      return static_cast<char_type*>(std::memmove(dest, src, count)); 
     } 

     static char_type* copy(char_type* dest, const char_type* src, std::size_t count) 
     { 
      return static_cast<char_type*>(std::memcpy(dest, src, count)); 
     } 

     static constexpr char_type to_char_type(const int_type& value) NOEXCEPT 
     { 
      return static_cast<char_type>(value); 
     } 

     static constexpr int_type to_int_type(const char_type& value) NOEXCEPT 
     { 
      return static_cast<int_type>(value); 
     } 

     static constexpr bool eq_int_type(const int_type& value1, const int_type& value2) NOEXCEPT 
     { 
      return value1 == value2; 
     } 

     static constexpr int_type eof() NOEXCEPT 
     { 
      return static_cast<int_type>(std::char_traits<char>::eof()); 
     } 

     static constexpr int_type not_eof(const int_type& value) NOEXCEPT 
     { 
      return (value == eof()) ? 0 : value; 
     } 
    }; 

    // Specialization of std::codecvt 
    template<> class codecvt< std::uint8_t, char, std::mbstate_t > : public locale::facet, public codecvt_base 
    { 
    public: 
     using internal_type = std::uint8_t; 
     using external_type = char; 
     using state_type = std::mbstate_t; 

     static std::locale::id id; 

     codecvt(std::size_t refs = 0) 
      : locale::facet(refs) 
     {} 

     std::codecvt_base::result out(state_type& state, const internal_type* from, const internal_type* from_end, const internal_type*& from_next, external_type* to, external_type* to_end, external_type*& to_next) const 
     { 
      return do_out(state, from, from_end, from_next, to, to_end, to_next); 
     } 

     std::codecvt_base::result in(state_type& state, const external_type* from, const external_type* from_end, const external_type*& from_next, internal_type* to, internal_type* to_end, internal_type*& to_next) const 
     { 
      return do_in(state, from, from_end, from_next, to, to_end, to_next); 
     } 

     std::codecvt_base::result unshift(state_type& state, external_type* to, external_type* to_end, external_type*& to_next) const 
     { 
      return do_unshift(state, to, to_end, to_next); 
     } 

     int length(state_type& state, const external_type* from, const external_type* from_end, std::size_t max) const 
     { 
      return do_length(state, from, from_end, max); 
     } 

     int max_length() const NOEXCEPT 
     { 
      return do_max_length(); 
     } 

     int encoding() const NOEXCEPT 
     { 
      return do_encoding(); 
     } 

     bool always_noconv() const NOEXCEPT 
     { 
      return do_always_noconv(); 
     } 

    protected: 
     virtual ~codecvt() {} 
     virtual std::codecvt_base::result do_out(state_type& state, const internal_type* from, const internal_type* from_end, const internal_type*& from_next, external_type* to, external_type* to_end, external_type*& to_next) const; 
     virtual std::codecvt_base::result do_in(state_type& state, const external_type* from, const external_type* from_end, const external_type*& from_next, internal_type* to, internal_type* to_end, internal_type*& to_next) const; 
     virtual std::codecvt_base::result do_unshift(state_type& state, external_type* to, external_type* to_end, external_type*& to_next) const; 
     virtual int do_length(state_type& state, const external_type* from, const external_type* from_end, std::size_t max) const; 
     virtual int do_max_length() const NOEXCEPT; 
     virtual int do_encoding() const NOEXCEPT; 
     virtual bool do_always_noconv() const NOEXCEPT; 
    }; // class codecvt 

    locale::id codecvt< std::uint8_t, char, std::mbstate_t >::id; 

    codecvt_base::result codecvt< std::uint8_t, char, std::mbstate_t >::do_out(state_type& state, const internal_type* from, const internal_type* from_end, const internal_type*& from_next, external_type* to, external_type* to_end, external_type*& to_next) const 
    { 
     (void) state; (void) from_end; (void) to_end; // Unused parameters 
     from_next = from; 
     to_next = to; 
     return codecvt_base::noconv; 
    } 

    codecvt_base::result codecvt< std::uint8_t, char, std::mbstate_t >::do_in(state_type& state, const external_type* from, const external_type* from_end, const external_type*& from_next, internal_type* to, internal_type* to_end, internal_type*& to_next) const 
    { 
     (void) state; (void) from_end; (void) to_end; // Unused parameters 
     from_next = from; 
     to_next = to; 
     return std::codecvt_base::noconv; 
    } 

    codecvt_base::result codecvt< std::uint8_t, char, std::mbstate_t >::do_unshift(state_type& state, external_type* to, external_type* to_end, external_type*& to_next) const 
    { 
     (void) state; (void) to_end; // Unused perameters 
     to_next = to; 
     return std::codecvt_base::noconv; 
    } 

    int codecvt< std::uint8_t, char, std::mbstate_t >::do_length(state_type& state, const external_type* from, const external_type* from_end, std::size_t max) const 
    { 
     (void) state; // Unused parameter 
     return static_cast<int>(std::min<std::size_t>(max, static_cast<std::size_t>(from_end - from))); 
    } 

    int codecvt< std::uint8_t, char, std::mbstate_t >::do_max_length() const NOEXCEPT 
    { 
     return 1; 
    } 

    int codecvt< std::uint8_t, char, std::mbstate_t >::do_encoding() const NOEXCEPT 
    { 
     return 1; 
    } 

    bool codecvt< std::uint8_t, char, std::mbstate_t >::do_always_noconv() const NOEXCEPT 
    { 
     return true; 
    } 
} // namespace std 


int main(int argc, char *argv []) 
{ 
    if (argc < 2) 
    { 
     std::cerr << argv[0] << " {file to read}" << std::endl; 
     return EXIT_FAILURE; 
    } 

    using stream_type = std::basic_ifstream< byte_type, std::char_traits<byte_type> >; 

    stream_type stream(argv[1], std::ifstream::in | std::ifstream::binary); 
    if (stream.is_open() == false) 
    { 
     std::cerr << "file not found" << std::endl; 
     return EXIT_FAILURE; 
    } 
    stream.exceptions(std::ifstream::badbit); 

    static const auto read_size = 4; 
    stream_type::char_type buffer[read_size]; 

    stream.read(buffer, read_size); 

    std::cout << "Got:" << stream.gcount() << std::endl; 

    return EXIT_SUCCESS; 
} 

संकलित करें और जी के साथ ++ चलाने के लिए और जीएनयू/लिनक्स:

$ g++ -std=c++11 -Wall -Wextra -pedantic stream.cpp -o stream && ./stream /dev/random 
terminate called after throwing an instance of 'std::bad_cast' 
    what(): std::bad_cast 
Aborted (core dumped) 

और विजुअल स्टूडियो एक्सप्रेस आर सी 2013 के साथ:

First-chance exception at 0x76A6C41F in traits test.exe: Microsoft C++ exception: std::bad_cast at memory location 0x0038F978. 
Unhandled exception at 0x76A6C41F in traits test.exe: Microsoft C++ exception: std::bad_cast at memory location 0x0038F978. 

बदलने byte_typechar जाने की उम्मीद उत्पादन देता है:

$ g++ -std=c++11 -Wall -Wextra -pedantic stream.cpp -o stream && ./stream /dev/random 
Got:4 

यह फेंकना std :: bad_cast क्यों है और मैं इसे कैसे ठीक कर सकता हूं?

+0

मैं का सामना करना पड़ रहा था @ कब्बी द्वारा उत्तर के साथ आपके और आपके पोस्ट की तुलना में एक ही समस्या बहुत उपयोगी थी! बस एक साइड नोट: ऐसा लगता है कि पूरी चीज 'std :: char_traits ' के विशेषज्ञता के बिना भी काम करती है, यानी 'std :: codecvt' और 'imbue' चाल का विशेषज्ञता पर्याप्त है। क्या मै गलत हु? –

उत्तर

5

मैं अपने जीसीसी (AIX पर 4.7.2) पर एक खराब_कास्ट पुन: पेश करने में सक्षम था।

कारण आप यह है कि जीसीसी पुस्तकालय कार्यान्वयन अनुकूलित basic_filebuf::xsgetn है (जो from basic_istream::read कहा जाता है) सादा सी fread कॉल करने के लिए फ़ाइल से पढ़ने के लिए अगर अपनी स्ट्रीम किसी भी स्थान रूपांतरण नहीं करने वाले (अर्थात, आप की कोशिश नहीं कर रहे हैं मिल गया एक यूटीएफ -8 या शायद जीबी 18030 फ़ाइल को यूटीएफ -32 स्ट्रिंग या कुछ में पढ़ें), जो बिल्कुल सही काम है। यह पता लगाने के लिए कि क्या यह गैर-परिवर्तित हो रहा है, यह आपकी स्ट्रीम में लगाए गए लोकेल के कोडेकवैट पहलू पर codecvt::always_noconv जांचता है ... जो मौजूद नहीं है।

आप को क्रियान्वित करने

std::cout << std::use_facet< 
        std::codecvt<std::uint8_t, char, std::mbstate_t> 
      >(stream.getloc()).always_noconv() << '\n'; 

मैं क्यों यह कार्य करता है (वे सिर्फ basic_fstream::read() में हर चार के लिए basic_filebuf::sgetc() कहते हैं?) को देखने के लिए दृश्य स्टूडियो के लिए पहुँच नहीं है द्वारा अपवाद पुन: पेश कर सकते हैं, लेकिन उपयोग करने के लिए किसी भी मामले में basic_filestream, आपको इस मामले में आंतरिक और बाहरी प्रकारों (uint8_t और char) के संयोजन के लिए एक कोडेकैट पहलू प्रदान करने की आवश्यकता है।

संपादित करें: आप बहुत करीब हैं, पिछले गायब टुकड़ा लाइन

stream.imbue(std::locale(stream.getloc(), 
      new std::codecvt<uint8_t, char, std::mbstate_t>)); 
कहीं भी stream.read से पहले

या वैकल्पिक रूप से वैश्विक रंगना है: std::locale::global(std::locale(std::locale(), new std::codecvt<uint8_t, char, std::mbstate_t>)); कहीं भी इससे पहले कि आप का निर्माण basic_ifstream

+0

सुझाव के लिए धन्यवाद। मैंने एक विशेष codecvt को शामिल करने के लिए कोड अपडेट किया है, लेकिन अब यह g ++ और विजुअल स्टूडियो दोनों पर std :: bad_cast फेंकता है। –

+0

@DrTwox imbue जोड़ने के बाद gcc के साथ मेरे लिए काम करता है (संपादन देखें) – Cubbi

+0

धन्यवाद! अगर मैं केवल एक से अधिक बार उठा सकता हूं! –

संबंधित मुद्दे