1

比较代码片段 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 快约 50 毫秒。这是为什么?如果 A 更快,我想使用它,但无论我尝试什么,我都无法让 Vector2!double 隐式转换为 Vector2!float。关于如何隐式转换这些类型的任何想法?或者是否有一些论点为什么我不应该隐含地投射它们?

我正在设置 GDC 和 LDC 以使用这些编译器执行此基准测试,但是如果这只是 DMD 优化问题,有人知道吗?

4

2 回答 2

3

就编译器而言,同一个模板的两个不同实例的共同点只不过是两个完全独立的类型。你可以声明

struct VectorFloat
{
    ...
}

struct VectorDouble
{
    ...
}

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

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

顺便说一句,如果需要,您可以使用 std.conv.to 而不是opCast直接调用。这种方式不太容易出错,从那时起,如果你搞砸了 define ,它会大喊大叫opCast,而编译器更有可能只是这样做,因为 cast 是一种非常生硬的工具。

于 2012-01-10T00:00:24.780 回答
1

您不应该隐式转换double精度floating 点,就像您不能隐式转换 from longto一样,int因为您会失去精度。

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

于 2012-01-09T22:59:35.297 回答