Sentiti libero di diffondere il nostro sito web e i nostri codici nelle tue reti, aiutaci ad espandere la nostra comunità.
Soluzione:
Poiché non ci sono ancora altre risposte, pubblico la mia soluzione che utilizza il metodo Boost.Iostreams . Anche se è abbastanza semplice, penso che ci dovrebbe essere una soluzione più semplice.
Per prima cosa creiamo una classe modello che modella il concetto di dispositivo Boost.Iostreams e funge da adattatore per un dispositivo stretto associato. Inoltra il file leggere, scrivere e cercare al dispositivo associato, ma regola i valori di posizione e dimensione del flusso per tenere conto della differenza di dimensione tra i tipi di carattere stretti e quelli larghi.
"basic_reinterpret_device.h"
#pragma once
#include
#include
#include
#include
// CategoryT: boost.iostreams device category tag
// DeviceT : type of associated narrow device
// CharT : (wide) character type of this device adapter
template< typename CategoryT, typename DeviceT, typename CharT >
class basic_reinterpret_device
{
public:
using category = CategoryT; // required by boost::iostreams device concept
using char_type = CharT; // required by boost::iostreams device concept
using associated_device = DeviceT;
using associated_char_type = typename boost::iostreams::char_type_of< DeviceT >::type;
static_assert( sizeof( associated_char_type ) == 1, "Associated device must have a byte-sized char_type" );
// Default constructor.
basic_reinterpret_device() = default;
// Construct from a narrow device
explicit basic_reinterpret_device( DeviceT* pDevice ) :
m_pDevice( pDevice ) {}
// Get the asociated device.
DeviceT* get_device() const { return m_pDevice; }
// Read up to n characters from the underlying data source into the buffer s,
// returning the number of characters read; return -1 to indicate EOF
std::streamsize read( char_type* s, std::streamsize n )
{
ThrowIfDeviceNull();
std::streamsize bytesRead = boost::iostreams::read(
*m_pDevice,
reinterpret_cast( s ),
n * sizeof( char_type ) );
if( bytesRead == static_cast( -1 ) ) // EOF
return bytesRead;
return bytesRead / sizeof( char_type );
}
// Write up to n characters from the buffer s to the output sequence, returning the
// number of characters written.
std::streamsize write( const char_type* s, std::streamsize n )
{
ThrowIfDeviceNull();
std::streamsize bytesWritten = boost::iostreams::write(
*m_pDevice,
reinterpret_cast( s ),
n * sizeof( char_type ) );
return bytesWritten / sizeof( char_type );
}
// Advances the read/write head by off characters, returning the new position,
// where the offset is calculated from:
// - the start of the sequence if way == ios_base::beg
// - the current position if way == ios_base::cur
// - the end of the sequence if way == ios_base::end
std::streampos seek( std::streamoff off, std::ios_base::seekdir way )
{
ThrowIfDeviceNull();
std::streampos newPos = boost::iostreams::seek( *m_pDevice, off * sizeof( char_type ), way );
return newPos / sizeof( char_type );
}
protected:
void ThrowIfDeviceNull()
{
if( ! m_pDevice )
throw std::runtime_error( "basic_reinterpret_device - no associated device" );
}
private:
DeviceT* m_pDevice = nullptr;
};
Per semplificare l'uso di questo modello, vengono creati alcuni modelli alias per i tag di dispositivo Boost.Iostreams più comuni. Sulla base di questi, creiamo modelli alias per costruire buffer e flussi di flusso compatibili con gli standard.
"reinterpret_stream.h"
#pragma once
#include "basic_reinterpret_device.h"
#include
#include
#include
#include
struct reinterpret_device_tag : virtual boost::iostreams::source_tag, virtual boost::iostreams::sink_tag {};
struct reinterpret_source_seekable_tag : boost::iostreams::device_tag, boost::iostreams::input_seekable {};
struct reinterpret_sink_seekable_tag : boost::iostreams::device_tag, boost::iostreams::output_seekable {};
template< typename DeviceT, typename CharT >
using reinterpret_source = basic_reinterpret_device< boost::iostreams::source_tag, DeviceT, CharT >;
template< typename DeviceT, typename CharT >
using reinterpret_sink = basic_reinterpret_device< boost::iostreams::sink_tag, DeviceT, CharT >;
template< typename DeviceT, typename CharT >
using reinterpret_device = basic_reinterpret_device< reinterpret_device_tag, DeviceT, CharT >;
template< typename DeviceT, typename CharT >
using reinterpret_device_seekable = basic_reinterpret_device< boost::iostreams::seekable_device_tag, DeviceT, CharT >;
template< typename DeviceT, typename CharT >
using reinterpret_source_seekable =
basic_reinterpret_device< reinterpret_source_seekable_tag, DeviceT, CharT >;
template< typename DeviceT, typename CharT >
using reinterpret_sink_seekable =
basic_reinterpret_device< reinterpret_sink_seekable_tag, DeviceT, CharT >;
template< typename DeviceT >
using reinterpret_as_wistreambuf = boost::iostreams::stream_buffer< reinterpret_source_seekable< DeviceT, wchar_t > >;
template< typename DeviceT >
using reinterpret_as_wostreambuf = boost::iostreams::stream_buffer< reinterpret_sink_seekable< DeviceT, wchar_t > >;
template< typename DeviceT >
using reinterpret_as_wstreambuf = boost::iostreams::stream_buffer< reinterpret_device_seekable< DeviceT, wchar_t > >;
template< typename DeviceT >
using reinterpret_as_wistream = boost::iostreams::stream< reinterpret_source_seekable< DeviceT, wchar_t > >;
template< typename DeviceT >
using reinterpret_as_wostream = boost::iostreams::stream< reinterpret_sink_seekable< DeviceT, wchar_t > >;
template< typename DeviceT >
using reinterpret_as_wstream = boost::iostreams::stream< reinterpret_device_seekable< DeviceT, wchar_t > >;
Esempi di utilizzo:
#include "reinterpret_stream.h"
void read_something_as_utf16( std::istream& input )
{
reinterpret_as_wistream< std::istream > winput( &input );
std::wstring wstr;
std::getline( winput, wstr );
}
void write_something_as_utf16( std::ostream& output )
{
reinterpret_as_wostream< std::ostream > woutput( &output );
woutput << L"сайт вопросов и ответов для программистов";
}
Questo è un lavoro in corso
Non si tratta di nulla da usare, ma probabilmente di un suggerimento da cui partire, se non si è ancora pensato di fare una cosa del genere. Se questo non è utile o se si riesce a trovare una soluzione migliore, sarò lieto di rimuovere o ampliare questa risposta.
Per quanto ho capito, vuoi leggere un file UTF-8 e semplicemente lanciare ogni singolo carattere in wchar_t.
Se è troppo quello che fanno le strutture standard, non si potrebbe scrivere la propria sfaccettatura.
#include
#include
#include
#include
#include
#include
class MyConvert
{
public:
using state_type = std::mbstate_t;
using result = std::codecvt_base::result;
using From = char;
using To = wchar_t;
bool always_noconv() const throw() {
return false;
}
result in(state_type& __state, const From* __from,
const From* __from_end, const From*& __from_next,
To* __to, To* __to_end, To*& __to_next) const
{
while (__from_next != __from_end) {
*__to_next = static_cast(*__from_next);
++__to_next;
++__from_next;
}
return result::ok;
}
result out(state_type& __state, const To* __from,
const To* __from_end, const To*& __from_next,
From* __to, From* __to_end, From*& __to_next) const
{
while (__from_next < __from_end) {
std::cout << __from << " " << __from_next << " " << __from_end << " " << (void*)__to <<
" " << (void*)__to_next << " " << (void*)__to_end << std::endl;
if (__to_next >= __to_end) {
std::cout << "partial" << std::endl;
std::cout << "__from_next = " << __from_next << " to_next = " <<(void*) __to_next << std::endl;
return result::partial;
}
To* tmp = reinterpret_cast(__to_next);
*tmp = *__from_next;
++tmp;
++__from_next;
__to_next = reinterpret_cast(tmp);
}
return result::ok;
}
};
int main() {
std::ofstream of2("test2.out");
std::wbuffer_convert conv(of2.rdbuf());
std::wostream wof2(&conv);
wof2 << L"сайт вопросов и ответов для программистов";
wof2.flush();
wof2.flush();
}
Non è nulla che si debba usare nel proprio codice. Se questo va nella giusta direzione, si bisogno di leggere la documentazione, compreso ciò che è necessario per questa sfaccettatura, cosa significano tutti questi puntatori e come si deve scrivere su di essi.
Se si vuole usare qualcosa di simile, bisogna pensare a quali argomenti del template usare per la sfaccettatura (se ce ne sono).
Aggiornamento Ho aggiornato il mio codice. La funzione out è ora più vicina a ciò che vogliamo, credo. Non è bello e solo un codice di prova, e non sono ancora sicuro del perché __from_next
non sia stato aggiornato (o mantenuto).
Attualmente il problema è che non possiamo scrivere sullo stream. Con gcc usciamo semplicemente dalla sincronizzazione di wbuffer_convert, per clang otteniamo un SIGILL.
Ricorda che sei autorizzato a spiegare se è stato utile.