【发布时间】:2016-04-27 08:33:37
【问题描述】:
我的库有几个自然映射到算术和逻辑/布尔运算符的操作。但是,这些操作需要除了lhs 和rhs 之外的其他参数。
这是我用ClipperLib 演示的几何示例:
假设我想创建一个多边形偏移运算符,它采用 2D 多边形和偏移增量并执行多边形偏移。这个例子来自 ClipperLib:
从数学上讲,此操作可以映射到采用多边形类型和数字类型的operator+。
然而,底层的实现需要更多的参数,例如斜接、精度等。
我想将数学符号的强大、表达力和简洁性与底层实现的控制力和精度结合起来。我想写:
// somehow materialize a properly parametrized operator+=()
poly += 10;
让这个做我想做的事。
有几个选项可以将这些参数注入二元重载运算符,但每个选项都有自己的缺点:
- 设置和使用类静态/全局(或线程本地)参数。
但是,使用全局变量不利于线程、可发现性、可读性和清理。 - 将额外参数保留为运算符输入类型的成员。
这给调用者增加了类型包装的负担,并且可能使代码更加繁琐。就一致性而言,这也不清楚哪些输入类型应该具有这些参数,以及在两者发生冲突或多个参数值的情况下会发生什么。
另外,如果我想多次执行该操作,我必须一遍又一遍地重新指定参数。
任何人都可以提出另一种可能适用于此的方法吗?
我正在考虑但不确定如何进行的一个选项是将重载的运算符作为模板函数放在单独的命名空间中。模板将在所需参数上进行参数化(假设它们在编译时已知),并且一旦实例化,操作符就会以某种方式被拉入当前可发现的命名空间,ADL 将在其中正确匹配它。 我不确定这是否/如何实现。
或者,使用相同的命名空间隐藏和显示技巧为运算符输入类型添加自动类型转换,以便它们自动包装为提供额外参数的类型。
这种命名空间隐藏和暴露+ADL可以做到吗?
我想这有点像给操作员一个类似 lambda 的行为。
【问题讨论】:
-
poly += CArgs(10).decorateWithPrecision(0.15).decorateWithLineWidth(1.5);怎么样? -
CArgs?您的意思是像选项 2 一样创建自定义包装器?虽然这种语法还不错,但我想知道是否可以以某种方式将额外的代码移入运算符实例化中。 -
是选项 2。您有 2 个选项。如果 args 是常量,您可以使用
CArg作为模板类。否则,您可以向构造函数添加更多参数,但这意味着装饰不是可选的。我会编写简单版本的代码并让优化器模块完成工作。 -
您可以尝试类似 std:: 的流类为您提供的使用操纵器更改其运算符的东西(例如
cout << hex << MyVar,以十六进制而不是十进制打印 MyVar)。我不确定我会为+操纵器选择哪种语法,但可能值得考虑。
标签: c++ operator-overloading template-meta-programming higher-order-functions argument-dependent-lookup