不同的是,标准库目前在Float上有一个+重载defined directly:
// TODO: These should not be necessary, since they're already provided by
// <T: FloatingPoint>, but in practice they are currently needed to
// disambiguate overloads. We should find a way to remove them, either by
// tweaking the overload resolution rules, or by removing the other
// definitions in the standard lib, or both.
extension ${Self} {
@_inlineable // FIXME(sil-serialize-all)
@_transparent
public static func + (lhs: ${Self}, rhs: ${Self}) -> ${Self} {
var lhs = lhs
lhs += rhs
return lhs
}
// [...]
}
(在运行 gyb.py 时,${Self} 将被 Float、Double 和 Float80 替换)
当涉及到重载决议时,+ 的 (Float, Float) -> Float 重载将在与 Float 操作数一起应用时胜过 (Value, Value) -> Float 重载,因为后者需要将它们从 Float 转换为 @ 987654337@.
但是Float 没有直接定义了> 重载; it's instead defined as a top-level generic function 超过 FloatingPoint 操作数:
@_transparent
public func > <T : FloatingPoint>(lhs: T, rhs: T) -> Bool {
return rhs.isLess(than: lhs)
}
当涉及到重载解决方案时,您的(Value, Value) -> Bool 重载将战胜这个通用重载,因为重载解决方案有利于非通用重载(请参阅切线in my answer here)。因此,您会反复出现。您可以通过将 > 的重载设置为泛型而不是 <T : Value>(T, T) -> Bool 来解决此问题,但随后它将不再适用于异构的 Value 操作数。
假设您希望运算符适用于异构操作数,一个万无一失的解决方案是通过使用嵌套的 Float 与 Numeric 和 Comparable 的一致性将调用调度到 > 和 +通用函数。这不能递归,因为
(Value, Value) -> Float 和 (Value, Value) -> Bool 都不能满足这些各自协议的 + 和 > 要求。
func + (lhs: Value, rhs: Value) -> Float {
func add<T : Numeric>(_ lhs: T, _ rhs: T) -> T {
return lhs + rhs
}
return add(lhs.get(), rhs.get())
}
func > (lhs: Value, rhs: Value) -> Bool {
func greaterThan<T : Comparable>(_ lhs: T, _ rhs: T) -> Bool {
return lhs > rhs
}
return greaterThan(lhs.get(), rhs.get())
}
(请注意,我们为+ 和> 这样做,因为+ (Float, Float) -> Float 重载可能会被删除以支持通用重载,这将导致与> 相同的问题)
另一种解决方案是完全避免分派到> 和+,而只是在Float 和+= 运算符上调用isLess(than:) 方法,模仿stdlib 实现:
func + (lhs: Value, rhs: Value) -> Float {
var lhsFloat = lhs.get()
lhsFloat += rhs.get()
return lhsFloat
}
func > (lhs: Value, rhs: Value) -> Bool {
return rhs.get().isLess(than: lhs.get())
}
虽然如果您为(inout Value, Value) -> Void 实现它的重载,则调用+= 可能会出现问题。