Tôi đã cố gắng nghĩ ra một cách tuyên bố các kiểu gõ mạnh, để bắt một loại lỗi nhất định trong giai đoạn biên dịch. Đó thường là trường hợp tôi nhập một int vào một số loại id hoặc một vectơ đến vị trí hoặc vận tốc:
typedef int EntityID;
typedef int ModelID;
typedef Vector3 Position;
typedef Vector3 Velocity;
Điều này có thể làm cho ý định của mã rõ ràng hơn, nhưng sau một đêm dài mã hóa, người ta có thể mắc những lỗi ngớ ngẩn như so sánh các loại id khác nhau, hoặc có thể thêm một vị trí vào vận tốc.
EntityID eID;
ModelID mID;
if ( eID == mID ) // <- Compiler sees nothing wrong
{ /*bug*/ }
Position p;
Velocity v;
Position newP = p + v; // bug, meant p + v*s but compiler sees nothing wrong
Thật không may, các đề xuất mà tôi đã tìm thấy cho các typedef được gõ mạnh bao gồm sử dụng boost, mà ít nhất với tôi không phải là một khả năng (ít nhất là tôi có c ++ 11). Vì vậy, sau một chút suy nghĩ, tôi nảy ra ý tưởng này và muốn điều hành nó bởi một ai đó.
Đầu tiên, bạn khai báo loại cơ sở là một mẫu. Tuy nhiên, tham số mẫu không được sử dụng cho bất kỳ định nghĩa nào:
template < typename T >
class IDType
{
unsigned int m_id;
public:
IDType( unsigned int const& i_id ): m_id {i_id} {};
friend bool operator==<T>( IDType<T> const& i_lhs, IDType<T> const& i_rhs );
};
Các hàm bạn bè thực sự cần phải được chuyển tiếp khai báo trước định nghĩa lớp, yêu cầu khai báo chuyển tiếp của lớp mẫu.
Sau đó, chúng tôi xác định tất cả các thành viên cho loại cơ sở, chỉ cần nhớ rằng đó là một lớp mẫu.
Cuối cùng, khi chúng tôi muốn sử dụng nó, chúng tôi đã gõ nó là:
class EntityT;
typedef IDType<EntityT> EntityID;
class ModelT;
typedef IDType<ModelT> ModelID;
Các loại bây giờ là hoàn toàn riêng biệt. Ví dụ, các hàm có EntityID sẽ gây ra lỗi trình biên dịch nếu bạn cố gắng cung cấp cho chúng ModelID. Ngoài việc phải khai báo các loại cơ sở dưới dạng mẫu, với các vấn đề đòi hỏi, nó cũng khá nhỏ gọn.
Tôi đã hy vọng bất cứ ai có ý kiến hoặc phê bình về ý tưởng này?
Một vấn đề nảy sinh trong khi viết điều này, trong trường hợp vị trí và vận tốc chẳng hạn, là tôi không thể chuyển đổi giữa các loại một cách tự do như trước. Trường hợp trước khi nhân một vectơ với vô hướng sẽ cho một vectơ khác, vì vậy tôi có thể làm:
typedef float Time;
typedef Vector3 Position;
typedef Vector3 Velocity;
Time t = 1.0f;
Position p = { 0.0f };
Velocity v = { 1.0f, 0.0f, 0.0f };
Position newP = p + v*t;
Với kiểu gõ mạnh mẽ của tôi, tôi phải nói với trình biên dịch rằng việc đa tốc độ theo Thời gian sẽ dẫn đến một Vị trí.
class TimeT;
typedef Float<TimeT> Time;
class PositionT;
typedef Vector3<PositionT> Position;
class VelocityT;
typedef Vector3<VelocityT> Velocity;
Time t = 1.0f;
Position p = { 0.0f };
Velocity v = { 1.0f, 0.0f, 0.0f };
Position newP = p + v*t; // Compiler error
Để giải quyết vấn đề này, tôi nghĩ rằng tôi phải chuyên môn hóa mọi chuyển đổi một cách rõ ràng, điều này có thể gây phiền toái. Mặt khác, giới hạn này có thể giúp ngăn ngừa các loại lỗi khác (giả sử, nhân Vận tốc với Khoảng cách, có lẽ, điều này sẽ không có ý nghĩa trong miền này). Vì vậy, tôi rất đau khổ và tự hỏi liệu mọi người có ý kiến gì về vấn đề ban đầu của tôi hay cách tiếp cận của tôi để giải quyết nó.