gpt4 book ai didi

c++ - 将窄 (char) 输入流重新解释为宽 (wchar_t) 流

转载 作者:可可西里 更新时间:2023-11-01 16:39:48 25 4
gpt4 key购买 nike

我得到了一个包含 UTF-16 编码字符串的 std::istream。想象一下像这样打开的 UTF-16 编码文本文件:

std::ifstream file( "mytext_utf16.txt", std::ios::binary );

我想将此流传递给采用 std::wistream& 参数的函数。我无法将文件流类型更改为 std::wifstream。

问题:标准库或 boost 库中是否有任何工具可以让我将 istream“重新解释”为 wistream?

我在想象一个类似于 std::wbuffer_convert 的适配器类除了它不应该做任何编码转换。基本上对于从适配器类读取的每个 wchar_t,它应该只从关联的 istream 读取两个字节并将它们reinterpret_cast 到 wchar_t。

我已经使用 boost::iostreams 创建了一个实现可以像这样使用并且像魅力一样工作:

std::ifstream file( "mytext_utf16.txt", std::ios::binary );

// Create an instance of my adapter class.
reinterpret_as_wide_stream< std::ifstream > wfile( &file );

// Read a wstring from file, using the adapter.
std::wstring str;
std::get_line( wfile, str );

那我为什么要问呢?因为我喜欢重用现有代码,而不是重新发明轮子。

最佳答案

由于还没有其他答案,我将发布使用 Boost.Iostreams 库的解决方案。虽然它非常简单,但我仍然认为应该有一个更简单的解决方案。

首先我们创建一个模板类来模拟 Boost.Iostreams device概念并用作相关窄设备的适配器。它将readwriteseek 操作转发到关联设备,但会调整流位置和大小值以适应窄字符和宽字符类型。

“basic_reinterpret_device.h”

#pragma once
#include <boost/iostreams/traits.hpp>
#include <boost/iostreams/read.hpp>
#include <boost/iostreams/write.hpp>
#include <boost/iostreams/seek.hpp>

// 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<associated_char_type*>( s ),
n * sizeof( char_type ) );

if( bytesRead == static_cast<std::streamsize>( -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<const associated_char_type*>( 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;
};

为了简化此模板的使用,我们为最常见的 Boost.Iostreams 设备标签创建了一些别名模板。基于这些,我们创建别名模板来构建标准兼容的流缓冲区和流。

“reinterpret_stream.h”

#pragma once
#include "basic_reinterpret_device.h"

#include <boost/iostreams/categories.hpp>
#include <boost/iostreams/traits.hpp>
#include <boost/iostreams/stream.hpp>
#include <boost/iostreams/stream_buffer.hpp>

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 > >;

使用示例:

#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"сайт вопросов и ответов для программистов";
}

关于c++ - 将窄 (char) 输入流重新解释为宽 (wchar_t) 流,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42332439/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com