Ifoda shablonlari - Expression templates - Wikipedia

Ifoda shablonlari a C ++ shablonni metaprogramlash iboralar joylashgan kompilyatsiya vaqtida hisoblashni ifodalovchi tuzilmalarni quradigan texnika faqat kerak bo'lganda baholanadi butun hisoblash uchun samarali kod ishlab chiqarish.[1] Shunday qilib ifoda shablonlari dasturchilarga C ++ tilini baholashning odatiy tartibini chetlab o'tishga va shu kabi optimallashtirishga imkon beradi. pastadir termoyadroviy.

Ifoda shablonlari Todd Veldxizen va Devid Vandevoorde tomonidan mustaqil ravishda ixtiro qilingan;[2][3] ularga ismini bergan Veldxuizen edi.[3] Ular amalga oshirish uchun mashhur texnika chiziqli algebra dasturiy ta'minot.[1]

Motivatsiya va namuna

Vakil beruvchi kutubxonani ko'rib chiqing vektorlar va ular bo'yicha operatsiyalar. Umumiy matematik operatsiyalardan biri ikkita vektorni qo'shishdir siz va v, yangi vektorni ishlab chiqarish uchun element-dono. Ushbu operatsiyani aniq C ++ dasturi an bo'ladi haddan tashqari yuklangan operator + yangi vektor ob'ektini qaytaradigan:

sinf Vec {    std::vektor<ikki baravar> elemlar;  jamoat:    Vec(hajmi_t n) : elemlar(n) {}    ikki baravar &operator[](hajmi_t men)      { qaytish elemlar[men]; }    ikki baravar operator[](hajmi_t men) konst { qaytish elemlar[men]; }    hajmi_t hajmi()               konst { qaytish elemlar.hajmi(); }};Vec operator+(Vec konst &siz, Vec konst &v) {    tasdiqlash(siz.hajmi() == v.hajmi());    Vec sum(siz.hajmi());    uchun (hajmi_t men = 0; men < siz.hajmi(); men++) {         sum[men] = siz[men] + v[men];    }    qaytish sum;}

Endi ushbu sinf foydalanuvchilari yozishlari mumkin Vec x = a + b; qayerda a va b ikkalasi ham Vec.

Kabi yondashuv bilan bog'liq bo'lgan murakkab iboralar Vec x = a + b + c samarasiz amalga oshirilmoqda. Amalga oshirish avval vaqtinchalik vektorni ishlab chiqaradi a + b, keyin elementlari bilan boshqa vektor hosil qiladi v qo'shildi. Hatto bilan qaytish qiymatini optimallashtirish bu kamida ikki marta xotirani ajratadi va ikkita ko'chadan talab qiladi.

Kechiktirilgan baho bu muammoni hal qiladi va C ++ da ruxsat berish orqali amalga oshiriladi operator + odatdagi turdagi ob'ektni qaytaring, aytaylik VecSum, bu ikki vektorning baholanmagan yig'indisini yoki a bilan vektorni ifodalaydi VecSumVa hokazo. Keyinchalik katta iboralar samarali tarzda quriladi ifoda daraxtlari faqat haqiqiyga tayinlanganda baholanadi Vec o'zgaruvchan. Ammo buning uchun baho berish uchun bunday daraxtlardan o'tishni talab qiladi, bu o'z-o'zidan qimmatga tushadi.[4]

Ifoda shablonlari faqat kompilyatsiya vaqtida mavjud bo'lgan ekspres daraxtlari yordamida kechiktirilgan baholashni amalga oshiradi. A-ga har bir topshiriq Vec, kabi Vec x = a + b + c, yangisini yaratadi Vec shablonni o'rnatishda kerak bo'lsa, konstruktor. Ushbu konstruktor uchta ishlaydi Vec; u kerakli xotirani ajratadi va keyin hisoblashni amalga oshiradi. Shunday qilib faqat bitta xotira ajratish amalga oshiriladi.

Ekspression andozalarini amalga oshirish misoli quyidagicha ko'rinadi. Asosiy sinf VecExpression har qanday vektor bilan ifodalangan ifodani ifodalaydi. Haqiqiy ifoda turiga shablon berilgan E amalga oshirilishi kerak qiziquvchan tarzda takrorlanadigan shablon namunasi. VecExpression kabi asosiy sinfning mavjudligi, shablon shablonlari ishlashi uchun qat'iyan zarur emas. Bu iboralarni boshqa turlardan ajratish uchun funktsiya argumenti turi sifatida xizmat qiladi (Vec konstruktori va operator + ning ta'rifiga e'tibor bering).

 1 shablon <yozuv nomi E> 2 sinf VecExpression { 3   jamoat: 4     ikki baravar operator[](hajmi_t men) konst  5     { 6         // Haqiqiy ifoda turiga delegatsiya. Bu dinamik polimorfizmga yo'l qo'ymaydi (C ++ da virtual funktsiyalar) 7         qaytish statik_cast<E konst&>(*bu)[men]; 8     } 9     hajmi_t hajmi()               konst { qaytish statik_cast<E konst&>(*bu).hajmi(); }10 };

The Vec class hali ham to'liq baholangan vektorli ifodaning koordinatalarini saqlaydi va subklassiga aylanadi VecExpression.

sinf Vec : jamoat VecExpression<Vec> {    std::vektor<ikki baravar> elemlar;  jamoat:    ikki baravar operator[](hajmi_t men) konst { qaytish elemlar[men]; }    ikki baravar &operator[](hajmi_t men)      { qaytish elemlar[men]; }    hajmi_t hajmi() konst               { qaytish elemlar.hajmi(); }    Vec(hajmi_t n) : elemlar(n) {}    // boshlang'ich ro'yxati yordamida vektorni qurish     Vec(std::boshlang'ich_list<ikki baravar> init) : elemlar(init) {}    // Vec har qanday VecExpression-dan tuzilishi mumkin va uni baholashga majbur qiladi.    shablon <yozuv nomi E>    Vec(VecExpression<E> konst& expr) : elemlar(expr.hajmi()) {        uchun (hajmi_t men = 0; men != expr.hajmi(); ++men) {            elemlar[men] = expr[men];        }    }};

Ikki vektorning yig'indisi yangi tur bilan ifodalanadi, VecSum, bu vektorli ifodalarning ixtiyoriy juftlariga qo'llanilishi uchun yig'indining chap va o'ng tomonlari turlarida shablonlangan. Haddan tashqari yuklangan operator + sifatida xizmat qiladi sintaktik shakar uchun VecSum konstruktor.

 1 shablon <yozuv nomi E1, yozuv nomi E2> 2 sinf VecSum : jamoat VecExpression<VecSum<E1, E2> > { 3     E1 konst& _u; 4     E2 konst& _v; 5  6 jamoat: 7     VecSum(E1 konst& siz, E2 konst& v) : _u(siz), _v(v) { 8         tasdiqlash(siz.hajmi() == v.hajmi()); 9     }10 11     ikki baravar operator[](hajmi_t men) konst { qaytish _u[men] + _v[men]; }12     hajmi_t hajmi()               konst { qaytish _v.hajmi(); }13 };14   15 shablon <yozuv nomi E1, yozuv nomi E2>16 VecSum<E1, E2>17 operator+(VecExpression<E1> konst& siz, VecExpression<E2> konst& v) {18    qaytish VecSum<E1, E2>(*statik_cast<konst E1*>(&siz), *statik_cast<konst E2*>(&v));19 }

Yuqoridagi ta'riflar bilan, ifoda a + b + c turi

VecSum<VecSum<Vec, Vec>, Vec>

shunday Vec x = a + b + c shablonni chaqiradi Vec Ushbu turdagi konstruktor unga o'xshash E shablon argumenti. Ushbu konstruktor ichida ilmoq tanasi

elemlar[men] = expr[men];

samarali ravishda kengaytirilgan (ning rekursiv ta'riflariga rioya qilgan holda operator + va operator [] Ushbu turdagi) ga

elemlar[men] = a.elemlar[men] + b.elemlar[men] + v.elemlar[men];

vaqtinchalik vektorlar kerak emas va har bir xotira blokidan faqat bittasi o'tadi.

Asosiy foydalanish:

 1 int asosiy() { 2     Vec v0 = {23.4,12.5,144.56,90.56}; 3     Vec v1 = {67.12,34.8,90.34,89.30}; 4     Vec v2 = {34.90,111.9,45.12,90.5}; 5      6     // Quyidagi topshiriq Vec ktorini chaqiradi, ular turini qabul qiladilar  7     // `VecExpression  const &`. Keyin pastadir tanasini kengaytiring  8     // a.elems [i] + b.elems [i] + c.elems [i] 9     Vec sum_of_vec_type = v0 + v1 + v2; 10 11     uchun (hajmi_t men=0; men<sum_of_vec_type.hajmi(); ++men)12         std::cout << sum_of_vec_type[men] << std::endl;13 14     // v0, v1, v2 dan tashqari qo'shimcha xotirani yaratmaslik uchun15     // quyidagilarni bajarish mumkin (GCC 5.3.0 da C ++ 11 bilan sinovdan o'tgan)16     avtomatik sum = v0 + v1 + v2;17     uchun (hajmi_t men=0; men<sum.hajmi(); ++men)18         std::cout << sum[men] << std::endl;19     // Ushbu holatda typeid (sum) VecSum , Vec> bo'lishiga e'tibor bering.20     // va ushbu operatsiyalar zanjiri davom etishi mumkin.21 }

Ilovalar

Izohlar shablonlari kutubxonalar mualliflari tomonidan chiziqli algebra uchun, ya'ni vektorlar bilan ishlash uchun juda foydali deb topildi va matritsalar raqamlar. Shablonni ishlatadigan kutubxonalar orasida Dlib,[5] Armadillo, Olov,[6] Blits ++,[7] Boost uBLAS,[8] Xususiy,[9] POOMA,[10] Stan matematikasi kutubxonasi,[11] va xtensor.[12] Ifoda shablonlari C ++ tilini ham tezlashtirishi mumkin avtomatik farqlash amalga oshirish,[13] ko'rsatilgandek Adept kutubxonasi.

Vektorli matematikadan tashqarida Ruhni ajratuvchi tizim ifodalash uchun ifoda shablonlaridan foydalanadi rasmiy grammatikalar va ularni tahlilchilarga kompilyatsiya qiling.

Adabiyotlar

  1. ^ a b Matsuzaki, Kiminori; Emoto, Kento (2009). Birlashma bilan jihozlangan parallel skeletlarni ekspression shablonlari bilan amalga oshirish. Proc. Xalqaro simp. funktsional tillarni amalga oshirish va qo'llash to'g'risida. 72-89 betlar.
  2. ^ Vandevoord, Devid; Josuttis, Nikolay (2002). C ++ shablonlari: to'liq qo'llanma. Addison Uesli. ISBN  0-201-73484-2.
  3. ^ a b Veldxizen, Todd (1995). "Ifoda shablonlari". C ++ hisoboti. 7 (5): 26-31. Arxivlandi asl nusxasi 2005 yil 10 fevralda.
  4. ^ Ibrohimlar, Dovud; Gurtovoy, Aleksey (2004). C ++ Andoza metaprogrammalashtirish: tushunchalar, vositalar va Boost va Beyond-dan foydalanish usullari. Pearson ta'limi.
  5. ^ https://dlib.net
  6. ^ https://bitbucket.org/blaze-lib/blaze
  7. ^ "Blitz ++ foydalanuvchi qo'llanmasi" (PDF). Olingan 12 dekabr, 2015.
  8. ^ "Asosiy chiziqli algebra kutubxonasini oshiring". Olingan 25 oktyabr, 2015.
  9. ^ Guennebaud, Gael (2013). Eigen: C ++ chiziqli algebra kutubxonasi (PDF). Eurographics / CGLibs.
  10. ^ Veldxizen, Todd (2000). Sizning kichkina tilingiz xavfsiz deb o'ylaganingizda: Java-da "Ifoda shablonlari". Xalqaro simp. Generativ va komponentlarga asoslangan dasturiy ta'minot. CiteSeerX  10.1.1.22.6984.
  11. ^ "Stan hujjatlari". Olingan 27 aprel, 2016.
  12. ^ "Eshittirish va dangasa hisoblash bilan ko'p o'lchovli massivlar". Olingan 18 sentyabr, 2017.
  13. ^ Hogan, Robin J. (2014). "C ++ da ekspression andozalari yordamida tezkor teskari rejimdagi avtomatik farqlash" (PDF). ACM Trans. Matematika. Dasturiy ta'minot. 40 (4): 26:1–26:16.