2012-01-09 4 views
1

Сравнить Код фрагментов A:D неявно Vector (T) типов

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), А является ~ 50мс быстрее, чем B. Почему это так? Если A быстрее, я хотел бы использовать его, но я не могу получить Vector2! Double, чтобы неявно использовать float Vector2! Независимо от того, что я пытаюсь. Любая идея о том, как я могу косвенно использовать эти типы? Или есть некоторые аргументы в пользу того, почему я не должен имплицитно их бросать?

Я настраиваю GDC и LDC, чтобы выполнить этот тест с этими компиляторами, но кто-нибудь знает, если это проблема оптимизации только для DMD?

ответ

1

Вы не должны неявно double к одной точности float точки Инг, так же, как вы не можете неявно преобразовать из long в int, потому что вы будете терять точность.

Большинство языков требуют, чтобы вы поняли, когда хотите потерять точность при конвертации. и лучше всего, если вы будете следовать существующим соглашениям на языке, а не выполнять свои собственные.

+0

Конечно, но я не могу неявно отбрасывать из Vector2! Float в Vector2! Double. –

+0

, затем добавьте 'opAssign (F) (Vector2! F l), если (isImplicitlyConvertible (F, T)) {x = l.x; y = l.y;}' –

3

Два разных экземпляра одного шаблона не имеют ничего общего, кроме двух совершенно разных типов, что касается компилятора. Вы можете объявить

struct VectorFloat 
{ 
    ... 
} 

struct VectorDouble 
{ 
    ... 
} 

вместо templatizing Vector2, и это не будет иметь никакого значения. Vector2!float и Vector!double - совершенно разные типы. И с любыми типами, которые вы заявляете, если вам нужны способы конвертировать между ними, вам придется объявить их - будь то opCast, alias this, конструкторы или что-то еще. Я считаю, что единственный способ, которым вы когда-либо будете получать неявный преобразование в работу с alias this, хотя, как указывает ratchet freak, неявное преобразование между поплавками и удвоениями - не, как D нормально работает и, возможно, является плохой идеей ,

Что касается того, почему A быстрее, чем B, я не знаю. Я бы предпочел, чтобы это было наоборот. Но в зависимости от того, что именно делает компилятор, он может измениться позже, и он может легко варьироваться от компилятора к компилятору. И поскольку вы видите только разницу в 50 мсек за 10 миллионов итераций, я бы пошел с версией, которая имеет больше смысла с точки зрения API (в зависимости от того, что вы думаете). Я бы поспорил с первым, хотя, просто потому, что я не думаю, что это хорошая идея, чтобы неявно конвертировать между float и double, но это зависит от вас, так как это ваш код.

Кстати, вы можете использовать std.conv.to вместо прямого вызова opCast, если хотите. Это менее подвержено ошибкам, так как тогда он будет кричать, если вы испортите определение opCast, тогда как компилятор, скорее всего, сделает это в любом случае, так как литье - это очень тупой инструмент.