السلام عليكم,
خلال تطوير uint, صادفت العديد من المشاكل(لاحصر لها :lol:) و لكن إحدى الحلول تضمنت الـ metaprogramming على أصول. القضية, أن المستخدم يقوم بكتابة شيء مشابه للتالي:
// unsigned integer: 128 bits uint<128> number;
هذه المئة و ثمانية و عشرون bits سوف تخزن في مصفوفة بكل تأكيد, و لكن ماهو نوع هذه المصفوفة؟
unsigned char unsigned short int unsigned int unsigned long unsigned long long
أضف لذلك, أن المكتبة لاتقبل كسوراً, مثلاً لا يوجد لدي عدد من الـ bits يكون مصفوفة مكونة من ثلاث عناصر "و ربع". باختصار, الحل كان لابد أن يكون من الشكل التالي:
template <std::size_t size>
struct type_factory
{
typedef typename type_factory_impl<size>::type type;
};
int main()
{
auto a = type_factory<8>::type(0); // unsigned char
auto b = type_factory<16>::type(0); // unsigned short int
auto c = type_factory<24>::type(0); // unsigned char
auto d = type_factory<32>::type(0); // unsigned long
auto e = type_factory<40>::type(0); // unsigned char
auto f = type_factory<48>::type(0); // unsigned short int
auto g = type_factory<56>::type(0); // unsigned char
auto h = type_factory<64>::type(0); // unsigned long long
}و الخوارزمية المتبعة في اختيار النوع المناسب:
if(size % bits<unsigned long long>::value == 0) typedef unsigned long long type; else if(size % bits<unsigned long>::value == 0) typedef unsigned long type; else if(size % bits<unsigned int>::value == 0) typedef unsigned int type; else if(size % bits<unsigned short int>::value == 0) typedef unsigned short int type; else if(size % bits<unsigned char>::value == 0) typedef unsigned char type; else static_assert(false, "The type should be multiple of 'unsigned char' size");
الحقيقة كان الحل ممتعاً, و خارجاً عن المألوف. حللت المشكلة بطريقتين: الأولى باستخدام الـ pattern matching أو ما يطلق عليه partial template specialization. فكرت قليلاً, ثم قمت بعمل refactoring لأن الكود و إن كان سهل الفهم نسبياً, إلا أنه طويل. لذلك قمت بكتابة meta if-else و اختصرت الحل :wink:
بالنسبة للحل الأول:
#include <cstddef>
#include <climits>
typedef unsigned char uchar;
typedef unsigned short int usint;
typedef unsigned int uint;
typedef unsigned long ulong;
typedef unsigned long long ulonglong;
// Returns how many bits in Unsigned_Type
template <typename Unsigned_Type>
struct bits
{ enum { value = sizeof(Unsigned_Type)*CHAR_BIT }; };
template <bool is_uchar>
struct unsigned_char
{
typedef unsigned char type;
static_assert(is_uchar,
"error: size must be multiple of 'unsigned char' size");
};
template <>
struct unsigned_char <true>
{ typedef uchar type; };
template <bool is_usint, std::size_t size>
struct unsigned_short_int
{ typedef typename
unsigned_char<size % bits<uchar>::value == 0>::type type; };
template <std::size_t size>
struct unsigned_short_int <true, size>
{ typedef usint type; };
template <bool is_uint, std::size_t size>
struct unsigned_int
{ typedef typename
unsigned_short_int<size % bits<usint>::value == 0, size>::type type; };
template <std::size_t size>
struct unsigned_int <true, size>
{ typedef uint type; };
template <bool is_ulong, std::size_t size>
struct unsigned_long
{ typedef typename
unsigned_int<size % bits<uint>::value == 0, size>::type type; };
template <std::size_t size>
struct unsigned_long <true, size>
{ typedef ulong type; };
template <bool is_ulonglong, std::size_t size>
struct unsigned_long_long
{ typedef typename
unsigned_long<size % bits<ulong>::value == 0, size>::type type; };
template <std::size_t size>
struct unsigned_long_long <true, size>
{ typedef ulonglong type; };
template <std::size_t size>
struct type_factory_impl
{ typedef typename
unsigned_long_long<size % bits<ulonglong>::value == 0, size>::type type; };
template <std::size_t size>
struct type_factory
{
typedef typename type_factory_impl<size>::type type;
};
int main()
{
auto a = type_factory<8>::type(0); // unsigned char
auto b = type_factory<16>::type(0); // unsigned short int
auto c = type_factory<24>::type(0); // unsigned char
auto d = type_factory<32>::type(0); // unsigned long
auto e = type_factory<40>::type(0); // unsigned char
auto f = type_factory<48>::type(0); // unsigned short int
auto g = type_factory<56>::type(0); // unsigned char
auto h = type_factory<64>::type(0); // unsigned long long
}أما الحل الثاني:
#include <cstddef>
#include <climits>
typedef unsigned char uchar;
typedef unsigned short int usint;
typedef unsigned int uint;
typedef unsigned long ulong;
typedef unsigned long long ulonglong;
// Returns how many bits in Unsigned_Type
template <typename Unsigned_Type>
struct bits
{ enum { value = sizeof(Unsigned_Type)*CHAR_BIT }; };
template <bool condition, typename Then, typename Else>
struct IF
{ typedef Else type; };
template <typename Then, typename Else>
struct IF <true, Then, Else>
{ typedef Then type; };
template <std::size_t size>
struct type_factory_impl
{
typedef typename
IF<size % bits<ulonglong>::value == 0, ulonglong,
typename IF<size % bits<ulong>::value == 0, ulong,
typename IF<size % bits<uint>::value == 0, uint,
typename IF<size % bits<usint>::value == 0, usint,
typename IF<size % bits<uchar>::value == 0, uchar, uchar>::type
>::type
>::type
>::type
>::type type;
};
template <std::size_t size>
struct type_factory
{
typedef typename type_factory_impl<size>::type type;
};
int main()
{
auto a = type_factory<8>::type(0); // unsigned char
auto b = type_factory<16>::type(0); // unsigned short int
auto c = type_factory<24>::type(0); // unsigned char
auto d = type_factory<32>::type(0); // unsigned long
auto e = type_factory<40>::type(0); // unsigned char
auto f = type_factory<48>::type(0); // unsigned short int
auto g = type_factory<56>::type(0); // unsigned char
auto h = type_factory<64>::type(0); // unsigned long long
}استخدمت static_assert و auto في visual studio 2010. لن أشرح الكود, لأني لا أعرف من أين أبدأ في شرحه. و لكن أرحب بأي سؤال أو مناقشة أو مثال آخر.
تحياتي...


