在阅读了名称查找规则,重载决议数十次后,我仍感到困惑。
我不确定我问的是我应该问的是什么,但无论如何。 想象一下,我有一些像第三方提供的功能:
namespace some_space {
template<typename Container>
void do_fancy_output(std::ostream& out, const Container& c) {
for (auto& el : c) { out << el; }
}
} // namespace
并且假设此函数附带了一组准备好的运算符<<
重载(为清楚起见,请在some_space
命名空间中定义它们)。除此之外,我有自己的一组重载。
问题是:有没有办法打开和关闭特定do_fancy_output()
来电的具体操作员重载?实现这一目标的一般架构指南是什么?
答案 0 :(得分:1)
operator <<
是一个像任何其他函数一样的函数。您无法在运行时动态更改函数实现。
你可以做的是:
// instead of:
out << el;
// do:
my_left_shift_operation_implementation(out, el);
,或者
如果真的喜欢使用<<
语法,请创建自己的class MyElement
,用于包装MyElement(el)
,然后在该类型上定义运算符。然后你会有:
out << my_el;
顺便说一句,如果重写操作员是你唯一能做的事情,我肯定会选择第一个解决方案。
如果您想在一种行为与另一种行为之间切换,请在my_left_shift_operation_implementation
。
你甚至可以制作一个Formatter
类,可以重写以提供不同的格式化实现。那你就做了:
out << my_formatter.format(el);
答案 1 :(得分:0)
您可以使用hack来覆盖函数中调用的运算符:
粗略地说,前三个步骤看起来像这样:
namespace special_format
{
// various functions for writing
void write(ostream& out, int);
void write(ostream& out, float);
// reference wrapper
template<typename value_type>
struct ref_wrapper
{
value_type const& value;
};
// convenience factory function
template<typename value_type>
ref_wrapper<value_type>
ref(value_type const& value)
{
ref_wrapper<value_type> r = {value};
return r;
}
}
我希望这部分是清楚的。序列包装器的第四部分更具挑战性,因为它包含更多的部分(我太懒了,不想破坏你编写它的全部乐趣)。首先,为了支持基于范围的for循环,您需要提供开始/结束迭代器访问。一种方法是简单地在命名空间中提供普通的begin()
和end()
函数,这些函数将在与该命名空间中的类型一起使用时找到。从那些,你只需返回一个包装容器的迭代器的迭代器。必须将value_type
,运算符*
和运算符->
调整为ref_wrapper
类型,以便我们的命名空间内的查找再次启动。