اذهب إلى المحتوى

القيم مصنفة النوع المعرَّفة من المستخدم User-Defined Literals في Cpp


محمد بغات

القيم الثنائية مصنفة النوع المُعرّفة من المستخدم (Self-made user-defined literal for binary)

رغم إمكانية كتابة عدد ثنائي في C++‎ 14 على النحو التالي:

int number =0b0001'0101; // ==21

إلا أننا في الأسطر التالية سنستعرض مثالًا مشهورًا يوفّر طريقة أخرى ذاتية التنفيذ للأعداد الثنائية. لاحظ أن برنامج توسيع القالب التالي يعمل في وقت التصريف.

template < char FIRST, char...REST > struct binary {
    static_assert(FIRST == '0' || FIRST == '1', "invalid binary digit");
    enum {
        value = ((FIRST - '0') << sizeof...(REST)) + binary < REST... > ::value
    };
};
template < > struct binary < '0' > {
    enum {
        value = 0
    };
};
template < > struct binary < '1' > {
    enum {
        value = 1
    };
};

// عامل قيمة خام مصنفة النوع
template < char...LITERAL > inline
constexpr unsigned int operator "" _b() {
    return binary < LITERAL... > ::value;
}
// عاملُ قيمةٍ خامٍ مصنَّفةِ النوع
template < char...LITERAL > inline
constexpr unsigned int operator "" _B() {
    return binary < LITERAL... > ::value;
}
#include <iostream>

int main() {
    std::cout << 10101_B << ", " << 011011000111_b << '\n'; // تطبع 21, 1735
}

القيم مصنفة النوع المعيارية المُعرّفة من المستخدم (Standard user-defined literals for duration)

الإصدار ≥ C++‎ 14

فيما يلي قيمُ مدةٍ مصنَّفةِ النوع، ومعرَّفة من قِبل المستخدم (duration user literals)، مصرح عنها في فضاء الاسم namespace std::literals::chrono_literals، حيث ‎literals‎ و ‎chrono_literals‎ هما فضاءا اسم ضمنيّان (inline namespaces). يمكن الوصول إلى هذه العوامل باستخدام using namespace std::literals و using namespace std::chrono_literals و using namespace std::literals::chrono_literals.

#include <chrono>
#include <iostream>

int main() {
    using namespace std::literals::chrono_literals;
    std::chrono::nanoseconds t1 = 600ns;
    std::chrono::microseconds t2 = 42us;
    std::chrono::milliseconds t3 = 51ms;
    std::chrono::seconds t4 = 61s;
    std::chrono::minutes t5 = 88min;
    auto t6 = 2 * 0.5h;
    auto total = t1 + t2 + t3 + t4 + t5 + t6;
    std::cout.precision(13);
    std::cout << total.count() << " nanoseconds" << std::endl; 
                          //  8941051042600 nanoseconds
      std::cout << std::chrono::duration_cast  <  std::chrono::hours >  (total).count() << " hours" << std::endl; // ساعتان
}

القيم مصنَّفة النوع المُعرّفة من المستخدم، ذات قيَم long double

يوضّح المثال التالي كيفية استخدام قيم مصنَّفة النوع، مُعرّفة من المستخدم وذات قيَم long double:

#include <iostream>

long double operator "" _km(long double val) {
    return val * 1000.0;
}
long double operator "" _mi(long double val) {
    return val * 1609.344;
}
int main() {
    std::cout << "3 km = " << 3.0_km << " m\n";
    std::cout << "3 mi = " << 3.0_mi << " m\n";
    return 0;
}

خرج هذا البرنامج هو:

3 km = 3000 m
3 mi = 4828.03 m

السلاسل النصية المجردة القياسية والمعرّفة من المستخدم (Standard user-defined literals for strings)

الإصدار ≥ C++‎ 14

فيما يلي سلاسل نصية مجردةٌ ومُعرّفة من المستخدم (string user literals)، مُصرَّح عنها في namespace std::literals::string_literals، حيث ‎literals‎ و ‎string_literals‎ هما فضاءا اسم مُضمّنان. ويمكن الوصول إلى هذه العوامل باستخدام using namespace std::literals و using namespace std::string_literals و using namespace std::literals::string_literals.

#include <codecvt>
#include <iostream>
#include <locale>
#include <string>

int main() {
    using namespace std::literals::string_literals;
    std::string s = "hello world"s;
    std::u16string s16 = u"hello world"s;
    std::u32string s32 = U"hello world"s;
    std::wstring ws = L"hello world"s;

    std::cout << s << std::endl;
    std::wstring_convert < std::codecvt_utf8_utf16 < char16_t > , char16_t > utf16conv;
    std::cout << utf16conv.to_bytes(s16) << std::endl;
    std::wstring_convert < std::codecvt_utf8_utf16 < char32_t > , char32_t > utf32conv;
    std::cout << utf32conv.to_bytes(s32) << std::endl;
    std::wcout << ws << std::endl;
}

ملاحظة: قد تحتوي السلاسل النصية المجردة على المحرف ‎\0‎، انظر المثال التالي:

// "foo"s النصية سينتج عنها C منشئات سلاسل
std::string s1 = "foo\0\0bar"; 

//  '\0' تحتوي هذه السلسلة النصية في وسطها على محرفين 
std::string s2 = "foo\0\0bar"s; 

القيم مصنفة النوع المركّبة المعرّفة من المستخدم (Standard user-defined literals for complex)

الإصدار ≥ C++‎ 14

فيما يلي، قيم مركّبة مصنفة النوع ومعرّفة من المستخدم، مُصرًّح عنها فيnamespace std::literals::complex_literals، حيث ‎literals‎ و ‎complex_literals‎ فضاءا اسم ضمنيان. يمكن الوصول إلى هذه العوامل باستخدام using namespace std::literals و using namespace std::complex_literals و using namespace std::literals::complex_literals.

#include <complex>
#include <iostream>

int main() {
    using namespace std::literals::complex_literals;

    std::complex < double > c = 2.0 + 1i; // {2.0, 1.}
    std::complex < float > cf = 2.0f + 1if; // {2.0f, 1.f}
    std::complex < long double > cl = 2.0L + 1il; // {2.0L, 1.L}

    std::cout << "abs" << c << " = " << abs(c) << std::endl; // abs(2,1) = 2.23607
    std::cout << "abs" << cf << " = " << abs(cf) << std::endl; // abs(2,1) = 2.23607
    std::cout << "abs" << cl << " = " << abs(cl) << std::endl; // abs(2,1) = 2.23607
}

هذا الدرس جزء من سلسلة دروس عن C++‎.

ترجمة -بتصرّف- للفصل Chapter 114: User-Defined Literals من كتاب C++ Notes for Professionals


تفاعل الأعضاء

أفضل التعليقات

لا توجد أية تعليقات بعد



انضم إلى النقاش

يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.

زائر
أضف تعليق

×   لقد أضفت محتوى بخط أو تنسيق مختلف.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   جرى استعادة المحتوى السابق..   امسح المحرر

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • أضف...