gpt4 book ai didi

c++ - 如何使我的函数对重载的 iostream 提取运算符具有粘性

转载 作者:可可西里 更新时间:2023-11-01 13:46:31 25 4
gpt4 key购买 nike

我正在做一个学校项目,我需要经常更改文本颜色。项目目标是目前仅适用于 Windows 的控制台应用程序。使用 Codeblocks 和 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";

我想要的是像setwsetprecision 等功能。所以我打开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 DID 坚持了程序的其余部分。为什么 ??(虽然它 100% 类似于 setw)。

如何使 setcoloursetw 一样???我需要这个功能来使我的程序更清晰和逻辑。

我还发现了这个: Which iomanip manipulators are sticky

但是那里的答案和评论只会让我感到困惑。显然,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> 中的虚函数.这些函数可以被覆盖,例如,通过委托(delegate)给基类实现来进行正常的格式化,然后再进行其他操作。

    在您的设置中,这种方法的关键问题是它不适用于非数字输出。例如,输出字符串不会重置任何内容。

  • 可以设置格式化标志 std::unitbuf在每个 [正确编写的] 输出运算符之后导致刷新。冲洗被翻译成调用pubsync()最终sync()在流中 std::basic_streambuf<cT> . sync()函数可以被覆盖。也就是说,该方法将安装自定义流缓冲区和标志 std::ios_base::unitbuf在设置将输出发送到原始流并调用 sync() 的 sone 标志时重置标志。

    除了有点做作之外,它还有一个问题,即您无法区分真正的冲洗和自动冲洗(srd::ios_base::unitbuf 的主要目的是让 std::cerr 冲洗)。此外,重置发生在第一个 std::ostream::sentry被摧毁。对于最有可能在格式化第一部分之后的复合值。

  • 无论如何,颜色格式化程序使用一个临时对象。该对象的构造函数可用于重置一些格式化标志。输出运算符将在相应对象“格式化”时设置必要的流信息(可能使用 mutable 成员)。当然,这意味着设置格式和输出需要在同一条语句中完成。此外,同一语句的所有输出都采用相同的格式。

我不知道在某些输出后处理格式化的任何其他方法。没有一种方法效果特别好。我宁愿使用类似守卫的方法来设置/取消设置标志,也不愿自作聪明。

关于c++ - 如何使我的函数对重载的 iostream 提取运算符具有粘性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33603939/

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