2011-10-19 33 views
19

Trong một thời gian tôi đã nhầm lẫn về hướng quá tải của toán tử D, nhưng bây giờ tôi nhận ra đó là một hệ thống đẹp ... nếu nó chỉ hoạt động với các loại lõi (int, float, vv). Hãy xem xét mã sau:Quá tải nhà điều hành thanh lịch trong D

struct Vector { 
    float X, Y; 

    void opOpAssign(string op)(Vector vector) { 
     X.opOpAssign!op(vector.X); // ERROR: no property "opOpAssign" for float 
     Y.opOpAssign!op(vector.Y); // ERROR: ditto 
    } 
} 

Đây sẽ là mã đẹp nếu nó hoạt động, khi nó quá tải tất cả các toán tử + =, - =, * =, v.v. Tuy nhiên, như bạn thấy, nó không hoạt động ra khỏi hộp. Tôi đã tạo giải pháp bằng cách sử dụng các mẫu (god I love D):

template Op(string op, T) { 
    void Assign(ref T a, T b) { 
     static if (op == "+") a += b; 
      else if (op == "-") a -= b; 
      else if (op == "*") a *= b; 
      else if (op == "/") a /= b; 
    } 
} 

struct Vector { 
    float X, Y; 

    void opOpAssign(string op)(Vector vector) { 
     Op!(op, typeof(X)).Assign(X, vector.X); 
     Op!(op, typeof(Y)).Assign(Y, vector.Y); 
    } 
} 

Điều này là tốt, chỉ muốn tôi giữ mọi thứ "trong nhà". Có cách nào để thực hiện công việc này mà không cần sự trợ giúp của mẫu không? Tôi biết tôi đang cầu kỳ ở đây, thấy rằng không có mất hiệu suất và không khó để nhập một mô-đun trong tình huống tôi cần phải làm điều này. Tôi chỉ tự hỏi nếu nó được xây dựng trong và tôi đang nhìn cái gì đó.

+0

Lưu ý rằng 'if' tĩnh không được tiếp tục sau 'if's sau' else'. Bạn phải lặp lại 'static' một lần nữa. – Bolpat

Trả lời

21

Hầu như tất cả các nhà khai thác quá tải trong D là mẫu theo định nghĩa. Lưu ý rằng void opOpAssign(string op)(Vector vector) có tham số mẫu là một chuỗi. Vì vậy, không có bạn không thể quá tải nó như là một chức năng không mẫu. Bây giờ, bạn không cần một mẫu thứ hai để làm điều đó (vì vậy nếu bằng cách hỏi xem bạn có cần một mẫu không, bạn có nghĩa là một mẫu trình trợ giúp, thì câu trả lời là không), nhưng hàm toán tử đã quá tải đã là một khuôn mẫu.

Cách kinh điển để làm những gì bạn bạn đang cố gắng làm ở đây là sử dụng mixins chuỗi:

void opOpAssign(string op)(Vector vector) 
{ 
    mixin("X" ~ op ~ "=vector.X;"); 
    mixin("Y" ~ op ~ "=vector.Y;"); 
} 
+0

Chết tiệt thật nhanh! Cảm ơn! –

13

này có nghĩa là để được kết hợp với mixins

void opOpAssign(string op)(Vector vector) { 
    mixin("X"~op~"=vector.X;"); 
    mixin("Y"~op~"=vector.Y;"); 
} 

chưa kể đến điều này có thể dễ dàng cùng với phép tính số học khác

Vector opBinary(string op)(Vector l)if(op=="+"||op=="-"){//only addition and subtraction makes sense for 2D vectors 
    mixin("return Vector(x"~op~"l.x,y"~op~"l.y;"); 
} 

///take in anything as long as a corresponding binaryOp exists 
///this essentially rewrites all "vec op= variable;" to "vec = vec op variable;" 
void opOpAssign(string op,T)(T l){ 
    this = this.binaryOp!op(l); 
} 

và thậm chí khác rộng Vector

Vector opBinary(string op)(real l)if(op=="*"||op=="/"){ 
    mixin("return Vector(x"~op~"l,y"~op~"l;"); 
} 

Vector opBinaryRight(string op)(real l)if(op=="*"){// for 2 * vec 
    return this*l; 
} 

lưu ý rằng các giới hạn được xác định là opBinary s có thể được chuyển đến opOpAssign nhưng bạn có thể đi cả hai cách (định nghĩa opBinary về opOpAssign)

+0

Johnathan đăng đầu tiên và giải thích thêm, vì vậy tôi đã đánh dấu câu trả lời của anh ấy, nhưng tôi cũng muốn cảm ơn bạn vì đã trả lời nhanh như vậy! –

+0

@FiL kiểm tra bản chỉnh sửa của tôi để biết thêm một chút quá tải về sự tốt lành –

Các vấn đề liên quan