Расширение SIMD3 с реализациями по умолчанию - PullRequest
0 голосов
/ 03 апреля 2019

У меня есть несколько protocols для vectors, используемых в моем приложении.У них есть default implementations в extensions, так что я могу реализовать все дополнительные функции для всех types of vectors.Теперь я хотел бы расширить SIMD3 на Scalar == Double, чтобы реализовать протокол Vector3D.Swift говорит мне, что если я укажу тип Scalar в расширении, то мне также нужно добавить все зависимости Vector3D для этого типа.Я не знаю, почему это не происходит автоматически, когда я выбираю связанный тип SIMD3, но все в порядке.Так что теперь у меня есть что-то вроде этого:

import UIKit
import simd

protocol DividableByInt {
    static func / (lhs: Self, rhs: Int) -> Self
}
protocol HasBasicinitializer {
    init()
}
protocol BasicMathOperations {
    static func + (lhs: Self, rhs: Self) -> Self
    static func - (lhs: Self, rhs: Self) -> Self
    static func * (lhs: Self, rhs: Self) -> Self
    static func / (lhs: Self, rhs: Self) -> Self
}
protocol Vector: BasicMathOperations, DividableByInt, HasBasicinitializer {
    associatedtype Scalar: (SIMDScalar & FloatingPoint)
    static var zero: Self { get }
    static func calculate(_ lhs: Self, _ rhs: Self, _ operation: (Scalar, Scalar) -> Scalar) -> Self
    static func calculate(_ lhs: Self, _ rhs: Scalar, _ operation: (Scalar, Scalar) -> Scalar) -> Self
    func allAxesValues() -> [Scalar]
}
extension Vector {
    static func + (lhs: Self, rhs: Self) -> Self { return calculate(lhs, rhs, +) }
    static func - (lhs: Self, rhs: Self) -> Self { return calculate(lhs, rhs, -) }
    static func * (lhs: Self, rhs: Self) -> Self { return calculate(lhs, rhs, *) }
    static func / (lhs: Self, rhs: Self) -> Self { return calculate(lhs, rhs, /) }
    static func * (lhs: Self, rhs: Scalar) -> Self { return calculate(lhs, rhs, *) }
    static func / (lhs: Self, rhs: Scalar) -> Self { return calculate(lhs, rhs, /) }
    static func / (lhs: Self, rhs: Int) -> Self { return calculate(lhs, Scalar(rhs), /) }
}
protocol Vector3D: Vector {
    init(x: Scalar, y: Scalar, z: Scalar)
    var x: Scalar { get }
    var y: Scalar { get }
    var z: Scalar { get }
}
extension Vector3D {
    func allAxesValues() -> [Scalar] {
        return [x, y, z]
    }
    static func calculate(_ lhs: Self, _ rhs: Self, _ operation: (Scalar, Scalar) -> Scalar) -> Self {
        return Self(x: operation(lhs.x, rhs.x), y: operation(lhs.y, rhs.y), z: operation(lhs.z, rhs.z))
    }
    static func calculate(_ lhs: Self, _ rhs: Scalar, _ operation: (Scalar, Scalar) -> Scalar) -> Self {
        return Self(x: operation(lhs.x, rhs), y: operation(lhs.y, rhs), z: operation(lhs.z, rhs))
    }
}

extension SIMD3: Vector3D where Scalar == Double {}

extension SIMD3: HasBasicinitializer {}
extension SIMD3: DividableByInt where Scalar == Double {}
extension SIMD3: Vector where Scalar == Double {
    static let zero = SIMD3(x: 0.0, y: 0.0, z: 0.0)
}
extension SIMD3: BasicMathOperations where Scalar == Double {}

Все работает автоматически, кроме последнего:

extension SIMD3: BasicMathOperations where Scalar == Double {}

Компилятор говорит:

Type 'SIMD3<Scalar>' does not conform to protocol 'BasicMathOperations'

Нотак как я добавил

extension SIMD3: Vector where Scalar == Double 

, он должен иметь все необходимые методы, реализованные уже, и иметь возможность продолжить.Протокол DividableByInt наследуется практически так же, и он может работать с реализацией от Vector extension.Почему BasicMathOperations не может использовать методы, реализованные в Vector extension?

Я знаю, что могу решить эту проблему, добавив

extension SIMD3: BasicMathOperations where Scalar == Double {
    static func + (lhs: SIMD3, rhs: SIMD3) -> SIMD3 { return calculate(lhs, rhs, +) }
    static func - (lhs: SIMD3, rhs: SIMD3) -> SIMD3 { return calculate(lhs, rhs, -) }
    static func * (lhs: SIMD3, rhs: SIMD3) -> SIMD3 { return calculate(lhs, rhs, *) }
    static func / (lhs: SIMD3, rhs: SIMD3) -> SIMD3 { return calculate(lhs, rhs, /) }
}

, но я не хочу удваивать этот код, поскольку он уже реализован в extension Vector, и его следует использовать вместо этого.

В конце я просто хочу расширить SIMD3 для реализации Vector3D.При необходимости с Scalar == Double или для любого из возможных скалярных типов.


Похоже, проблема в том, что в SIMD3 уже реализованы такие функции, как +, -, /, *, и компилятор не может определить, какиеодин на выбор.Я мог бы удалить реализацию по умолчанию из Vector, и это решило бы проблему для SIMD3, но тогда мне нужно было бы отдельно реализовать ее для всех других типов, соответствующих вектору.Я использую это также для SCNVector3 и CGPoint.Я не знаю что лучше.Может быть, есть какое-то лучшее решение, чтобы я мог реализовать его для всех других типов, кроме SIMD3?

1 Ответ

0 голосов
/ 03 апреля 2019

ОК, я думаю, что нашел лучшее решение. Я переместил реализацию по умолчанию BasicMathOperations из extension Vector в отдельный протокол, а затем добавил наследование к этому новому протоколу для всех типов, которые соответствуют Vector, кроме SIMD3.

// Adds default implementation for BasicMathOperation
protocol VectorWithDefaultImplementationForBasicMathOperations: Vector {}

extension VectorWithDefaultImplementationForBasicMathOperations {
    static func + (lhs: Self, rhs: Self) -> Self { return calculate(lhs, rhs, +) }
    static func - (lhs: Self, rhs: Self) -> Self { return calculate(lhs, rhs, -) }
    static func * (lhs: Self, rhs: Self) -> Self { return calculate(lhs, rhs, *) }
    static func / (lhs: Self, rhs: Self) -> Self { return calculate(lhs, rhs, /) }
}

extension CGPoint: VectorWithDefaultImplementationForBasicMathOperations {}
extension SCNVector3: VectorWithDefaultImplementationForBasicMathOperations {}

Если кто-нибудь знает лучшее решение, пожалуйста, дайте мне знать, но я думаю, что это уже довольно хорошо.

...