D 隐式强制转换 Vector(T) 类型



比较代码片段 A:

struct Vector2(T) {
    // ...
    auto opCast(U)() {
        return U(x, y);
    }
    void opOpAssign(string op)(Vector2 vector) {
        mixin ("x" ~ op ~ "= vector.x;");
        mixin ("y" ~ op ~ "= vector.y;");
    }
}
void main() {
    auto fVec = Vector2!float(1.5, 1.5);
    auto dVec = Vector2!double(1.5, 1.5);
    // Benchmark: Loop following 10 million times.
    fVec += cast(Vector2!float)  dVec;
    dVec -= cast(Vector2!double) fVec;
}

与 B:

struct Vector2(T) {
    // ...
    void opOpAssign(string op, U)(Vector2!U vector) {
        mixin ("x" ~ op ~ "= vector.x;");
        mixin ("y" ~ op ~ "= vector.y;");
    }
}
void main() {
    auto fVec = Vector2!float(1.5, 1.5);
    auto dVec = Vector2!double(1.5, 1.5);
    // Benchmark: Same as A.
    fVec += dVec;
    dVec -= fVec;
}

在我的基准测试(DMD,Win7(中,A比B快~50ms。这是为什么?如果 A 更快,我想使用它,但无论我尝试什么,我都无法让 Vector2!double 隐式转换为 Vector2!float。关于如何隐式转换这些类型的任何想法?或者有什么争论为什么我不应该隐含地投射它们?

我正在设置 GDC 和 LDC 来使用这些编译器进行此基准测试,但有谁知道这是否是仅 DMD 的优化问题?

就编译器而言,同一模板的两个不同实例化只有两个完全独立的类型。您可以声明

struct VectorFloat
{
    ...
}
struct VectorDouble
{
    ...
}

而不是模板化Vector2,这不会有什么区别。 Vector2!floatVector!double是完全不同的类型。对于您声明的任何类型,如果您想在它们之间进行转换,则必须声明它们 - 无论是opCastalias this、构造函数还是其他什么。我相信你唯一能获得式转换工作的方法就是使用 alias this ,尽管正如棘轮怪胎指出的那样,在浮点数和双精度之间隐式转换不是 D 通常的工作方式,可以说是一个坏主意。

至于为什么A比B快,我不知道。我实际上本来会期望它是相反的。但是,根据编译器正在执行的操作,它可能会在以后发生变化,并且很容易因编译器而异。由于您在 1000 万次迭代中只看到 50 毫秒的差异,因此我会选择从 API 角度更有意义的版本(无论您认为哪个(。不过,我会争论使用第一个,仅仅是因为我认为在 float 和 double 之间隐式转换不是一个好主意,但这取决于你,因为它是你的代码。

顺便说一下,如果需要,您可以使用 std.conv.to 而不是直接调用opCast。这样就不容易出错了,因为那样的话,如果你搞砸了定义opCast,它会大喊大叫,而编译器无论如何都更有可能这样做,因为 cast 是一种非常生硬的工具。

不应将

double隐式转换为单个精度float点,就像不能从long隐式转换为int一样,因为会丢失精度。

大多数语言要求您在转换时明确说明何时要失去精度。 最好遵循语言中的现有约定,而不是强制执行自己的约定。

相关内容

  • 没有找到相关文章

最新更新