Saya sudah mencoba memikirkan cara mendeklarasikan typedef yang sangat diketik, untuk menangkap kelas bug tertentu pada tahap kompilasi. Seringkali saya mengetikkan int menjadi beberapa jenis id, atau vektor untuk posisi atau kecepatan:
typedef int EntityID;
typedef int ModelID;
typedef Vector3 Position;
typedef Vector3 Velocity;
Ini bisa membuat maksud kode lebih jelas, tetapi setelah semalaman pengkodean, orang mungkin membuat kesalahan konyol seperti membandingkan berbagai jenis id, atau menambahkan posisi ke kecepatan mungkin.
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
Sayangnya, saran yang saya temukan untuk typedef yang sangat diketik termasuk menggunakan boost, yang setidaknya bagi saya bukan kemungkinan (saya punya setidaknya c ++ 11). Jadi setelah berpikir sebentar, saya menemukan ide ini, dan ingin menjalankannya oleh seseorang.
Pertama, Anda mendeklarasikan tipe dasar sebagai templat. Parameter template tidak digunakan untuk apa pun dalam definisi, namun:
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 );
};
Fungsi teman sebenarnya harus dideklarasikan ke depan sebelum definisi kelas, yang memerlukan deklarasi maju dari kelas template.
Kami kemudian mendefinisikan semua anggota untuk tipe dasar, hanya mengingat bahwa itu adalah kelas templat.
Akhirnya, ketika kita ingin menggunakannya, kita mengetikkannya sebagai:
class EntityT;
typedef IDType<EntityT> EntityID;
class ModelT;
typedef IDType<ModelT> ModelID;
Jenis sekarang sepenuhnya terpisah. Fungsi yang mengambil EntityID akan menimbulkan kesalahan kompiler jika Anda mencoba untuk memberi mereka ModelID, misalnya. Selain harus mendeklarasikan tipe dasar sebagai templat, dengan masalah yang menyertainya, itu juga cukup kompak.
Saya berharap ada yang punya komentar atau kritik tentang ide ini?
Salah satu masalah yang terlintas dalam pikiran ketika menulis ini, dalam hal posisi dan kecepatan misalnya, adalah bahwa saya tidak dapat mengkonversi antar tipe dengan bebas seperti sebelumnya. Di mana sebelum mengalikan vektor dengan skalar akan memberikan vektor lain, jadi saya bisa melakukan:
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;
Dengan typedef saya yang sangat diketik saya harus memberi tahu kompiler bahwa multypling Velocity by a Time menghasilkan Posisi.
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
Untuk mengatasi ini, saya pikir saya harus mengkhususkan setiap konversi secara eksplisit, yang dapat menjadi masalah. Di sisi lain, batasan ini dapat membantu mencegah jenis kesalahan lainnya (katakanlah, mengalikan Kecepatan dengan Jarak, mungkin, yang tidak masuk akal dalam domain ini). Jadi saya bingung, dan bertanya-tanya apakah orang punya pendapat tentang masalah asli saya, atau pendekatan saya untuk menyelesaikannya.