Derleme aşamasında belirli bir hata sınıfı yakalayabilmek için, güçlü bir şekilde yazılmış typedefleri bildirmenin bir yolunu düşünmeye çalışıyorum. Bu, çoğu zaman çeşitli kimlik türlerine bir int veya tanımlayacağım veya konum veya hız için bir vektör yazacağım durum budur:
typedef int EntityID;
typedef int ModelID;
typedef Vector3 Position;
typedef Vector3 Velocity;
Bu, kodun amacını daha net bir hale getirebilir, ancak uzun bir kodlama gecesinden sonra, farklı türdeki kimlikleri karşılaştırmak veya belki de bir hıza pozisyon eklemek gibi aptalca hatalar yapabilir.
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
Maalesef, güçlü bir şekilde yazılmış typedef'ler için bulduğum öneriler, en azından benim için olasılık olmayan bir destek kullanıyor (en azından c ++ 11 var). Bu yüzden biraz düşündükten sonra, bu fikre ulaştım ve bir başkası tarafından çalıştırmak istedim.
İlk olarak, taban türünü şablon olarak bildirirsiniz. Ancak template parametresi tanımdaki hiçbir şey için kullanılmaz:
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 );
};
Arkadaş işlevlerinin gerçekte, şablon tanımının ileri bir bildirimini gerektiren sınıf tanımından önce bildirilmesi gerekir.
Daha sonra tüm üyeleri sadece bir şablon sınıfı olduğunu hatırlatarak temel tip için tanımladık.
Son olarak, kullanmak istediğimizde, onu şöyle tanımlarız:
class EntityT;
typedef IDType<EntityT> EntityID;
class ModelT;
typedef IDType<ModelT> ModelID;
Türler şimdi tamamen ayrı. EntityID alan işlevler, örneğin bunun yerine bir ModelID beslemeye çalışırsanız derleyici hatası verir. Temel türleri şablon olarak ilan etmek zorunda kalmanın yanı sıra, gerektirdiği konularla birlikte oldukça kompakt bir yapıya sahiptir.
Birisinin bu fikir hakkında yorum veya eleştirisi olmasını umuyordum.
Bunu yazarken aklıma gelen bir konu, örneğin konumlar ve hızlar durumunda, türler arasında eskisi kadar özgürce dönemediğimdir. Bir vektörü skaler ile çarpmadan önce başka bir vektör verirse, ben de yapabilirdim:
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;
Güçlü yazılmış typedef'imle derleyiciye, bir Hızın bir Zamana göre çarpılmasının bir Pozisyonla sonuçlandığını söylemek zorundayım.
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
Bunu çözmek için, her türlü dönüşümü açıkça uzmanlaşmam gerektiğini düşünüyorum, bu biraz rahatsız edici olabilir. Öte yandan, bu sınırlama diğer hata türlerini önlemeye yardımcı olabilir (diyelim ki, Hızı bir Mesafe ile çarpmak, belki de bu alanda anlamlı olmaz). Bu yüzden paramparça oluyorum ve insanların asıl meselem hakkında herhangi bir fikrinin ya da çözme yaklaşımım hakkında herhangi bir fikri olup olmadığını merak ediyorum.