如何使我的函数对重载的 iostream 提取运算符具有粘性
How can I make my function sticky for overloaded iostream extraction operators
>我正在做一个学校项目,我需要经常更改文本颜色。项目目标是当前仅适用于 Windows 的控制台应用。将代码块与 MinGW 一起使用进行调试。我不是菜鸟,而是中级。
所以在代码中到处使用它很丑陋:
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), __col._colour_code);
即使我把它包装在一个函数中,它仍然很麻烦和丑陋,因为你无法继续你的cout链。您已经打破了链条,因为您必须在新语句中调用SetColour
,例如:
SetColour(GRAY); cout << setcol(PURPLE) << " ID:[";
SetColour(AQUA); cout << song.GetID();
SetColour(GRAY); cout << "]" << " ";
SetColour(GREEN); cout << song.GetTitle();
SetColour(WHITE); cout << " by ";
SetColour(BRIGHT); cout << song.GetArtist() << "n";
我想要的是像setw
、setprecision
等功能。所以我打开iomainp.h
,寻找一些提示:
struct _Setw { int _M_n; };
inline _Setw
setw(int __n)
{ return { __n }; }
template<typename _CharT, typename _Traits>
inline basic_istream<_CharT, _Traits>&
operator>>(basic_istream<_CharT, _Traits>& __is, _Setw __f)
{
__is.width(__f._M_n);
return __is;
}
template<typename _CharT, typename _Traits>
inline basic_ostream<_CharT, _Traits>&
operator<<(basic_ostream<_CharT, _Traits>& __os, _Setw __f)
{
__os.width(__f._M_n);
return __os;
}
所以我以 100% 类似的方式创建了一个自己的新功能:
enum Colour { BLACK=0x00, DARK_GREEN=0x02, WHITE=0x07, GRAY,
BLUE=0x09, GREEN, AQUA, RED, PURPLE, YELLOW, BRIGHT };
struct _colour_struct
{
uint8_t _colour_code;
};
inline _colour_struct setcolour (Colour colour_foregrnd, Colour colour_backgrnd =BLACK)
{
uint8_t colour_code = colour_backgrnd;
colour_code <<= 4;
colour_code |= colour_foregrnd;
return { colour_code };
}
namespace std
{
template<typename _CharT, typename _Traits>
inline basic_ostream<_CharT, _Traits>&
operator<<(basic_ostream<_CharT, _Traits>& __os, _colour_struct __col)
{
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), __col._colour_code);
return __os;
}
}
惊喜!(对我来说(它的工作!!例如:
cout << setcolour(GRAY) << " ID:[" << setcolour(AQUA) << song.GetID() << setcolour(GRAY) << "]" << " "
<< setcolour(GREEN) << song.GetTitle()
<< setcolour(WHITE) << " by "<< setcolour(BRIGHT) << song.GetArtist() << "n";
但请考虑以下代码的输出:
std::cout << std::setw(20) << setcolour(AQUA) << "1st time" << "n";
std::cout << "2nd time" << "n";
std::cout << "3rd time" << "n";
请注意,setw
没有坚持,它是第二行的重置。如何??(调试显示没有执行额外的调用来重置它。
但我的setcolour
确实坚持了程序的其余部分。为什么??(尽管它 100% 类似于 setw
(。
我怎样才能让setcolour
像setw
???一样我需要此功能来使我的程序更加干净和合乎逻辑。
我也发现了这个:哪些 iomanip 机械手是粘性的
但是那里的答案和评论只会让我感到困惑。当然,setw
调用 cout.width(0(,但调试显示没有这样的调用,也没有在iomanip.h
中找到这样的代码行。也不明白那里的答案。请解释一下。
编辑
也许我问这个问题并不直接。就像cout.width(0)
(在setw
的上下文中(每次都被调用一样,
如何让我的SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 0x0)
(在setcolour
的上下文中(每次都被调用???我应该如何处理这个问题?
宽度是专门处理的:所有内置运算符都会在输出对象后重置宽度。在代码或调试器中看不到相应的width(0)
调用这一事实并不意味着它不存在!它可以是内联的,而不是命中断点,例如。关于代码,您需要查看,例如,在std::num_put<...>
的实现中:实际的输出运算符不包含代码,但do_put()
函数包含代码。
要重置其他格式标志,您需要挂接到每个输出操作后调用的某个操作。但是,机会不多:流不支持在每个对象之后进行通用自定义。以下是可以做的事情,但我会重新评论,让格式标志保持粘性。将宽度特别化可以说是一个错误:
-
数字格式是通过
std::num_put<cT>
中的do_put()
虚函数完成的。这些函数可以被覆盖,例如,通过委托给基类实现来执行正常的格式化,然后是其他东西。在您的设置中,此方法的关键问题是它不适用于非数字输出。例如,输出字符串不会重置任何内容。
-
可以设置格式化标志
std::unitbuf
导致每个[正确写入]输出运算符后刷新。冲洗被转换为pubsync()
的调用,并最终sync()
流std::basic_streambuf<cT>
。可以覆盖sync()
函数。也就是说,该方法是在设置sone标志时安装自定义流缓冲区和标志std::ios_base::unitbuf
,该标志将输出发送到原始流并在调用时sync()
重置标志。除了有点做作之外,它还存在一个问题,即您无法区分真正的冲洗和自动冲洗(
srd::ios_base::unitbuf
的主要目的是使std::cerr
刷新(。此外,重置发生在销毁的第一个std::ostream::sentry
。对于最有可能在格式化第一部分之后的复合值。 -
无论如何,颜色格式化程序都使用临时对象。此对象的析构函数可用于重置一些交换标志。输出运算符将在相应对象被"格式化"(可能使用
mutable
成员(时在相应对象上设置必要的流信息。当然,这意味着设置格式和输出需要从同一语句完成。此外,同一语句上的所有输出都采用相同的格式。
我不知道任何其他方法来处理某些输出后的格式化。没有一种方法特别有效。我宁愿使用类似警卫的方法来设置/取消设置标志,而不是试图变得聪明。
请注意,setw 没有坚持,它是第二行中的重置。如何??
使用 cout << setcolour(AQUA)
时,您将对稍后使用的程序的状态进行持久更改。
std::setw()
的情况并非如此。 std::setw()
仅设置下一个输出的宽度,然后将宽度重置为零。有关更多详细信息,请参阅 http://en.cppreference.com/w/cpp/io/manip/setw。具体而言,《说明》:
如果调用以下任何函数,流的 width 属性将重置为零(表示"未指定"(:
- 输入
operator>>(basic_istream&, basic_string&)
operator>>(basic_ostream&, char*)
- 输出
- 重载 1-7 的
basic_ostream::operator<<()
(在num_put::put()
的第 3 阶段(operator<<(basic_ostream&, char)
和operator<<(basic_ostream&, char*)
operator<<(basic_ostream&, basic_string&)
std::put_money
(money_put::put())
内std::quoted
(与输出流一起使用时(
- 从包含m行的文件中提取n行,必要时(惰性地)重复该文件
- 如何从 std::atomic 中提取指针 T<T>?
- 为什么istream不支持右值提取
- 是否可以用"iostream"包装现有的TCP/OOpenSSL会话
- 需要从 istream 和 ostream 派生 iostream
- 如何设置一个范围来提取我想要获得的信息
- std::带有自定义缓冲区的 iostream 不允许我写入
- 视觉工作室项目.提取源文件夹名称
- C++17 - 使用自定义分配器的节点提取/重新插入 - 适用于 clang++/libc++,但不适用于 libstd
- 从字符串中提取整数并形成一个数组
- C ++中的StringStream有助于使用向量从字符串中提取逗号分隔的整数,而不是空格分隔的整数,为什么?
- asn1c 不会从 asn.1 模块中提取八位字节字符串的默认值
- 从 std::vector<无符号字符>切片中提取 int?
- 在C++中使用重载提取运算符时出现问题
- 在 Qt(C++) 中使用 QProcess 解压缩 - 提取目录问题
- C++(.cpp文件和.h文件)拆分代码并添加一个函数,提取 - 这很容易吗?
- 无法从 std::string 中提取C++ Unicode 符号
- 如何使我的函数对重载的 iostream 提取运算符具有粘性
- 为什么当我提取到"char"和"int"时,IOStream的EOF标志行为会有所不同?
- iostream插入器和提取器可以是类成员而不是全局重载吗?