我一直在实现一个编解码器来处理输出流的缩进。它可以像这样使用并且工作正常:
std::cout << indenter::push << "im indentet" << indenter::pop << "\n im not..."
然而,当我发现我的std::codecvt
代码和.std::ostream
std::cout
std::ofstream
std::ostringstream
std::ostream
facet 构造正常,代码编译,不会抛出任何异常……只是没有std::codecvt
调用 的成员函数。
对我来说,这非常令人困惑,我不得不花费大量时间弄清楚它std::codecvt
不会对非文件 I/O 流做任何事情。
是否有任何理由std::codecvt
没有被所有继承的类使用std::ostream
?
此外,有没有人知道我可以依靠哪些结构来实现压头?
编辑:这是我所指的语言的一部分:
通过 std::basic_fstream 执行的所有文件 I/O 操作都使用流中包含的语言环境的 std::codecvt<CharT, char, std::mbstate_t> 方面。
来源:https ://en.cppreference.com/w/cpp/locale/codecvt
更新1:
我做了一个小例子来说明我的问题:
#include <iostream>
#include <locale>
#include <fstream>
#include <sstream>
static auto invocation_counter = 0u;
struct custom_facet : std::codecvt<char, char, std::mbstate_t>
{
using parent_t = std::codecvt<char, char, std::mbstate_t>;
custom_facet() : parent_t(std::size_t { 0u }) {}
using parent_t::intern_type;
using parent_t::extern_type;
using parent_t::state_type;
virtual std::codecvt_base::result do_out (state_type& state, const intern_type* from, const intern_type* from_end, const intern_type*& from_next,
extern_type* to, extern_type* to_end, extern_type*& to_next) const override
{
while (from < from_end && to < to_end)
{
*to = *from;
to++;
from++;
}
invocation_counter++;
from_next = from;
to_next = to;
return std::codecvt_base::noconv;
}
virtual bool do_always_noconv() const throw() override
{
return false;
}
};
std::ostream& imbueFacet (std::ostream& ostream)
{
ostream.imbue(std::locale { ostream.getloc(), new custom_facet{} });
return ostream;
}
int main()
{
std::ios::sync_with_stdio(false);
std::cout << "invocation_counter = " << invocation_counter << "\n";
{
auto ofstream = std::ofstream { "testFile.txt" };
ofstream << imbueFacet << "test\n";
}
std::cout << "invocation_counter = " << invocation_counter << "\n";
{
auto osstream = std::ostringstream {};
osstream << imbueFacet << "test\n";
}
std::cout << "invocation_counter = " << invocation_counter << "\n";
}
我会invocation_counter
在流式传输后增加std::ostringstream
,但事实并非如此。
更新 2:
经过更多研究,我发现我可以使用std::wbuffer_converter
. 引用https://en.cppreference.com/w/cpp/locale/wbuffer_convert
std::wbuffer_convert
是类型的流缓冲区的包装器,std::basic_streambuf<char>
使其外观为std::basic_streambuf<Elem>
. 所有通过执行的 I/O 都std::wbuffer_convert
经历了由方面 Codecvt 定义的字符转换。[...]此类模板使隐式字符转换功能
std::basic_filebuf
可用于任何std::basic_streambuf
.
这样我可以将一个方面应用于std::ostringstream
:
auto osstream = std::ostringstream {};
osstream << "test\n";
auto facet = custom_facet{};
std::wstring_convert<custom_facet, char> conv;
auto str = conv.to_bytes(osstream.str());
但是,我失去了使用流操作符连接构面的能力<<
。
这让我更加困惑,为什么std::codecvt
所有输出流都没有隐式使用。所有输出流都继承自std::basic_streambuf
其适合使用的接口std::codecvt
,它只是使用输入和输出字符序列,完全实现在std::basic_streambuf
.
那么为什么解析的std::codecvt
实现是 instd::basic_filebuf
而不是std::basic_streambuf
呢?毕竟std::basic_filebuf
继承...std::basic_streambuf
要么我对流在 C++ 中的工作方式有一些基本的误解,要么std::codecvt
在标准中集成得不好。也许这就是它被标记为已弃用的原因?