Ane*_*777 5 c++ windows console iomanip
我正在做一个学校项目,我需要经常更改文本颜色.项目目标是目前仅适用于Windows的控制台应用.将代码块与MinGW一起使用进行调试.我不是菜鸟,但是中级.
所以在代码中无处不在使用它是丑陋的:
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), __col._colour_code);
Run Code Online (Sandbox Code Playgroud)
即使我把它包装在一个函数中,它仍然很麻烦和丑陋,因为你不能继续你的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";
Run Code Online (Sandbox Code Playgroud)
我想要的是这样的功能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;
}
Run Code Online (Sandbox Code Playgroud)
所以我以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;
}
}
Run Code Online (Sandbox Code Playgroud)
惊喜!(对我来说)它的工作!! 例如:
cout << setcolour(GRAY) << " ID:[" << setcolour(AQUA) << song.GetID() << setcolour(GRAY) << "]" << " "
<< setcolour(GREEN) << song.GetTitle()
<< setcolour(WHITE) << " by "<< setcolour(BRIGHT) << song.GetArtist() << "\n";
Run Code Online (Sandbox Code Playgroud)
但请考虑此代码的输出:
std::cout << std::setw(20) << setcolour(AQUA) << "1st time" << "\n";
std::cout << "2nd time" << "\n";
std::cout << "3rd time" << "\n";
Run Code Online (Sandbox Code Playgroud)
请注意,setwDID没有粘住,它在第二行重置.怎么样 ??(调试显示没有执行额外的调用来重置它.)
但是我的setcolourDID坚持了该计划的其余部分.为什么?(虽然它的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()函数包含。
要重置其他格式化标志,您需要挂钩到每个输出操作后调用的某些操作。不过,机会并不多:流不支持每个对象之后的通用自定义。以下是可以完成的操作,但我建议保留格式标记。将宽度设置为特殊可以说是一个错误:
数字格式化是通过do_put()中的虚拟函数完成的std::num_put<cT>。这些函数可以被重写,例如,通过委托给基类实现来执行正常的格式化,然后进行其他操作。
在您的设置中,这种方法的关键问题是它不适用于非数字输出。例如,输出字符串不会重置任何内容。
可以设置格式化标志,std::unitbuf在每个[正确编写的]输出运算符之后导致刷新。刷新被转换为对流的调用pubsync(),并最终sync()在流上std::basic_streambuf<cT>。该sync()函数可以被覆盖。也就是说,该方法将在设置将输出std::ios_base::unitbuf发送到原始流并在调用时重置标志的标志时安装sync()自定义流缓冲区和标志。
除了有点做作之外,它还有一个问题,即您无法区分真正的冲洗和自动冲洗(其主要目的srd::ios_base::unitbuf是冲洗std::cerr)。此外,重置发生在第一个std::ostream::sentry被破坏时。对于最有可能在第一部分格式化之后的复合值。
无论如何,颜色格式化程序使用临时对象。该对象的 dstructor 可用于重置一些格式标志。当对象被“格式化”时(可能使用成员mutable),输出运算符将在相应对象上设置必要的流信息。当然,这意味着设置格式和输出需要在同一语句中完成。此外,同一语句上的所有输出都接收相同的格式。
我不知道有任何其他方法可以在输出后处理格式化。这些方法都没有特别有效。我宁愿使用类似守卫的方法来设置/取消设置标志,而不是试图变得聪明。
| 归档时间: |
|
| 查看次数: |
246 次 |
| 最近记录: |