gpt4 book ai didi

c++ - 如何实现自动添加分隔符的自定义粘性操纵器?

转载 作者:搜寻专家 更新时间:2023-10-31 00:35:57 24 4
gpt4 key购买 nike

Python 中的 print 函数使用可自定义的分隔符自动分隔其参数。有什么方法可以通过使用流操纵器在 C++ 中模拟这种行为吗?

也就是下面的C++代码:

std::cout << custom::sep(", ") << 1 << "two" << 3 << std::endl;

应该类似于以下 Python 代码:

print(1, "two", 3, sep=", ")

期望的输出是:

1, two, 3

我将如何着手实现 custom::sep?它似乎比您的标准自定义操纵器更棘手,因为它不能只更改流中的下一个项目,例如 herehere .它应该是粘性的,直到下一个 custom::sepstd::endl。此外,它不能只适用于数字或某些类型,例如 here .它应该适用于任何可流式传输类型。

最佳答案

The issue with the solution you posted is that it relies on customizing the way integers get formatted using facets. Unfortunately, I do not think there is a corresponding facility which would work for arbitrary types.

有。您可以使用流的底层缓冲区来获取您想要的内容。缓冲区是最终收集字符序列以进行维护的地方。以下代码生成一个流缓冲区,其中包含对您希望使用其字符序列的对象的引用。我们设置了 std::ios_base::unitbuf 格式标志,以便在每次输出操作时刷新流(因此我们可以将分隔符添加到末尾)。

通过扩展,它还允许您卸载分隔符并确保在此过程中没有内存泄漏:

#include <iostream>
#include <string>

namespace custom
{
struct sep_impl
{
sep_impl(std::string const& separator);
std::string separator;
};

sep_impl sep(std::string const& str)
{
return sep_impl(str);
}

std::ostream& nosep(std::ostream& os);
}

int separatorEnabled()
{ static int idx = std::ios_base::xalloc(); return idx; }
int getSeparator() { static int idx = std::ios_base::xalloc(); return idx; }

struct custom_separator : std::streambuf
{
public:
custom_separator(std::ostream& _stream) : stream(_stream)
{ }

int_type overflow(int_type c)
{
return stream.rdbuf()->sputc(c);
}

int sync()
{
if (stream.iword(separatorEnabled()))
{
void*& p = stream.pword(getSeparator());
stream << *static_cast<std::string*>(p);
return 0;
}
return stream.rdbuf()->pubsync();
}
private:
std::ostream& stream;
};

void cleanup(std::ios_base::event evt, std::ios_base& str, int idx)
{
if (str.iword(separatorEnabled()) && evt == std::ios_base::erase_event)
{
void*& p = str.pword(idx);
delete static_cast<std::string*>(p);
str.iword(separatorEnabled()) = false;
}
}

std::ostream& set_separator(std::ostream& os, const custom::sep_impl& manip)
{
if (!os.bad())
{
os.pword(getSeparator()) = new std::string(manip.separator);
os.register_callback(cleanup, getSeparator());
}

return os;
}

std::ostream& operator<<(std::ostream& os, const custom::sep_impl& manip)
{
std::ostream* p = os.tie();
if (p && !p->iword(separatorEnabled()))
{
set_separator(*p, manip);
p->iword(separatorEnabled()) = true;
}

return os << std::unitbuf;
}

namespace custom
{
sep_impl::sep_impl(std::string const& _sep) : separator(_sep) { }

std::ostream& nosep(std::ostream& os)
{
cleanup(std::ios_base::erase_event, *os.tie(), getSeparator());
os.tie(nullptr);
return os << std::nounitbuf;
}

void install_separator(std::ostream& o1, std::ostream& o2)
{
static custom_separator csep(o2);
o1.rdbuf(&csep);
o1.tie(&o2);
}
}

int main()
{
std::ostream os(nullptr);
custom::install_separator(os, std::cout);

os << custom::sep(", ") << 4 << 2 << custom::nosep;
}

我确信还有改进的余地,所以如果有人有任何建议,我们将不胜感激。

Live Example

关于c++ - 如何实现自动添加分隔符的自定义粘性操纵器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22840258/

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