std::ios_base::register_callback 的索引参数有什么作用?
What does the index parameter of std::ios_base::register_callback do?
参见 http://www.cplusplus.com/reference/ios/ios_base/register_callback/
我以为index
会控制触发回调的顺序,但事实似乎并非如此。此参数有什么作用?
下面是一个代码片段:
5 void testfn (std::ios::event ev, std::ios_base& stream, int index)
6 {
7 switch (ev)
8 {
9 case stream.copyfmt_event:
10 std::cout << "copyfmt_eventn"; break;
11 case stream.imbue_event:
12 std::cout << "imbue_eventn"; break;
13 case stream.erase_event:
14 std::cout << "erase_eventn"; break;
15 }
16 }
17
18 void testfn2 (std::ios::event ev, std::ios_base& stream, int index)
19 {
20 switch (ev)
21 {
22 case stream.copyfmt_event:
23 std::cout << "copyfmt_event 2n"; break;
24 case stream.imbue_event:
25 std::cout << "imbue_event 2n"; break;
26 case stream.erase_event:
27 std::cout << "erase_event 2n"; break;
28 }
29 }
30
31 int main () {
32 std::ofstream filestr;
33 filestr.register_callback (testfn,0);
34 filestr.register_callback (testfn2,1);
35 filestr.imbue (std::cout.getloc());
36
37 std::ofstream filestr2;
38 filestr2.register_callback (testfn,1);
39 filestr2.register_callback (testfn2,0);
40 filestr2.imbue (std::cout.getloc());
41 return 0;
42 }
下面是输出:
jefferson@ubuntu:~/inheritance$ g++ -std=c++14 stream_callbacks.cpp
jefferson@ubuntu:~/inheritance$ ./a.out
imbue_event 2
imbue_event
imbue_event 2
imbue_event
erase_event 2
erase_event
erase_event 2
erase_event
我有一个利用它的库(libaddr)。
输出地址向量时,我的代码将默认使用逗号 (",") 作为默认分隔符:
addr::addr::vector_t addresses;
...define the addresses somehow...
std::cout << addresses; // defaults to commas between each address
但是,您可能需要一个空格或换行符:
std::cout << addr::setaddrsep(" ") << addresses;
std::cout << addr::setaddrsep("n") << addresses;
在这里,我展示了如何使用结构和函数来更改分隔符,如上所示(大部分源代码都在 addr.h 中,请参阅 addr.cpp 了解xalloc()
调用):
struct _setaddrsep
{
std::string f_sep;
};
template<typename _CharT, typename _Traits>
inline std::basic_ostream<_CharT, _Traits> &
operator << (std::basic_ostream<_CharT, _Traits> & out, _setaddrsep sep)
{
int const index(get_ostream_index());
_ostream_info * info(static_cast<_ostream_info *>(out.pword(index)));
if(info == nullptr)
{
info = new _ostream_info;
out.pword(index) = info;
out.register_callback(basic_stream_event_callback, index);
}
info->f_sep = sep.f_sep;
return out;
}
正如我们所看到的,我有一个调用get_ostream_index()
它返回您提到的索引。以下函数为我的libaddr
环境调用一次xalloc()
函数。之后,索引在整个程序运行过程中保持不变。换句话说,此索引由ios_base
库分配给您的类。
int get_ostream_index()
{
cppthread::guard lock(*cppthread::g_system_mutex);
if(!g_ostream_index_allocated)
{
g_ostream_index_allocated = true;
g_ostream_index = std::ios_base::xalloc();
}
return g_ostream_index;
}
警告:您可能想编写int g_ostream_index = xalloc();
来直接初始化全局变量。这很危险,至少有两个原因:(1)你不能100%确定xalloc()
可以这么早被称为(虽然可能);(2) 如果您有另一个使用输出流的全局函数,则g_ostream_index
可能尚未初始化(即,C++您无法控制全局初始化的顺序)。使用函数,您可以确保它按顺序发生。此外,如果您编写 .so 或 .DLL,初始化将在您自己的程序初始化之前进行,因此只要库本身不包含另一个尝试使用该g_ostream_index
的全局,您就是安全的。就个人而言,我宁愿安全也不愿后悔。这些错误可能很难调试,因为它发生在调用main()
之前。
稍后打印地址时,它可以检查是否找到了用户指定的参数:
template<typename _CharT, typename _Traits, typename _ContainerT>
inline typename std::enable_if<
std::is_same<_ContainerT, addr::vector_t>::value
|| std::is_same<_ContainerT, addr::set_t>::value
, std::basic_ostream<_CharT, _Traits>>::type &
operator << (std::basic_ostream<_CharT, _Traits> & out, _ContainerT const & addresses)
{
std::string sep(",");
_ostream_info * info(static_cast<_ostream_info *>(out.pword(get_ostream_index())));
if(info != nullptr)
{
sep = info->f_sep;
}
bool first(true);
for(auto const & a : addresses)
{
if(first)
{
first = false;
}
else
{
out << sep;
}
out << a;
}
return out;
}
如我们所见,我将一个名为sep
的变量设置为默认分隔符","
。然后我检查out.pword(index)
,如果不nullptr
,则用用户定义的分隔符替换sep
。
这是我的_ostream_info
结构,其中包括两个参数:
struct _ostream_info
{
addr::string_ip_t f_mode = addr::string_ip_t::STRING_IP_ALL;
std::string f_sep = std::string(",");
};
我认为 99.9% 的情况下,您应该使用指向结构的指针,这样您就可以随着时间的推移添加任意数量的参数,而无需编辑所有流函数以从long
转到指针(即您始终可以在结构中有一个long
开始)。
另一个重要点:如果使用pword()
功能,回调非常重要,因为在这种情况下,您分配的内存必须在回调收到std::ios_base::erase_event
事件时释放。
还必须实现copy_fmt
以确保它复制缓冲区(或使用某种引用计数)。
当然,在您的示例中,索引为 0 和索引 1 的回调不是您的。这两个调用可能会破坏系统定义的回调(即每个索引肯定只有一个回调)。由于我的xalloc()
返回 2,因此我想 0 和 1 已经是系统定义的,这当然是您的调用似乎有效的原因。
- 传递给std::function template的template参数究竟代表什么
- 什么..(省略号)作为函数原型中唯一的函数参数,C++?
- C++部分概念 id:显式模板规范顺序/第一个参数的特殊状态的原因是什么?
- 引用捕获和在 lambda 中通过引用发送参数有什么区别 (C++)
- C++有什么方法可以在既不调用函数模板也不提供其模板参数的情况下引用函数模板?
- 读取大文件(>2GB)(文本文件包含以太网数据)并通过不同参数随机访问数据的最佳方法是什么?
- 未命名的非类型模板参数有什么意义?
- 有什么方法可以将具有不同模板参数的模板类实例放入向量中?
- 什么是仅调用一次并调用参数的控制台应用
- 在模板参数中使用 {} 在 type_trait{} 中时,其作用是什么<T>?
- 在 C 和 C++ 中作为函数参数,int **a 和 int a[][] 之间有什么确切的区别
- 为什么或在什么情况下,你会将参数作为C++中的引用(或指针)传递给函数?
- 没有大小参数的CString::GetBuffer()做什么
- 可变参数模板和省略号有什么区别?
- 当通知迭代器参数初始化为空列表的开头时,list::insert 行为是什么?
- C++ [错误] 声明'char '隐藏参数。什么意思?
- 用相同的参数声明两个构造函数的最偶像化的方法是什么?
- 使用作为参数返回的指针的最佳做法是什么
- C++构造函数调用 boost::文件系统::p ath 作为参数 - 什么也没发生
- 如果我只想指定哈希函数,我应该传递给unordered_map的存储桶计数参数什么?