constexpr менен компиляция учурунда программалоо
Эсептөөнү аткаруу убактысынан компиляторго которуу - шаблон метапрограммалоонун заманбап мураскери
constexpr үй-бүлөсү компиляторго функция же өзгөрмө компиляция учурунда эсептелүүгө жарактуу экенин билдирет. Аргументтердин өзү компиляция убагынын константалары болгондо, натыйжаны компилятор эсептеп, аны бинардык файлга литерал катары бышырат - аткаруу убагында процессорго эч кандай иш калбайт. Шаблон метапрограммалоо (TMP) эсептөөнү табышмактай окулган рекурсивдүү шаблон инстанциялары түрүндө коддогон жерде, constexpr сизге кадимки функцияларды - циклдер, локалдык өзгөрмөлөр жана if менен - жазууга мүмкүнчүлүк берет, алар кошумча компиляция учурунда да иштейт.
constexprфункциясын (компиляцияда иштеши мүмкүн)constevalфункциясынан (иштеши милдеттүү) айырмалай аласыз;constexprөзгөрмөсү качан компиляцияда эсептөөнү мажбурлаарын жана бул жөнөкөйconstдан кантип айырмаланарын билесиз;if constexprменен бутактарды компиляцияда таштап, SFINAE жана тег-диспетчерлөө кодуңуздун көбүнөн баш тарта аласыз;constexprэмне үчүн маанилерди эсептөө үчүн TMP ни негизинен алмаштырганын түшүндүрүп, шаблондор жана TMP дагы эле керек болгон учурларды атай аласыз.
Тема бул курстагы Шаблон метапрограммалоо, SFINAE жана чектөөлөр жана Концепттер (C++20) темаларына негизделет. Сиз рекурсивдүү шаблонду жана тип трейтин окуй аласыз деп болжолдонот.
1. constexpr функциялары - убада эмес, уруксат
constexpr функциясы - бул бир кошумча касиети бар кадимки функция: ага компиляция учурунда иштөөгө уруксат берилет. Чын эле иштейби же жокпу, толугу менен чакыруу ордуна көз каранды. Константалык эсептөө контекстинде константалык аргументтер менен чакырылса, компилятор аны эсептеп, жоопту литерал катары сактайт. Кадимки аткаруу убагындагы маани менен чакырылса, ал башка функциялар сыяктуу процессордо иштейт. Бир аныктама - эки мүмкүн болгон аткаруу убагы.
constexpr long factorial(int n) {
long result = 1; // C++14: локалдык өзгөрмөлөр, циклдер
for (int i = 2; i <= n; ++i) // жана мутация - баары уруксат
result *= i;
return result;
}
constexpr long f5 = factorial(5); // компилятор эсептейт -> 120
int r = read_int(); // кайсы бир аткаруу убагындагы маани
long fr = factorial(r); // ошол эле функция, аткаруу убагында иштейт
Бул Шаблон метапрограммалоо темасында кездешкен рекурсивдүү шаблондук факториалга караганда канчалык окулуктуу экенине көңүл буруңуз. Бул кадимки императивдик код. C++14 тен бери constexpr функциясы циклдерди, бир нече операторду, локалдык өзгөрмөлөрдү жана аларды өзгөртүүнү камтышы мүмкүн; C++11 деги бир гана return чектөөсү эчак жоюлду.
Константалык эсептөө контексти деген эмне? Тил константалык туюнтманы талап кылган жерлер:
constexprөзгөрмөсүнүн инициализатору жеstatic_assertшарты;- типтик эмес шаблон аргументи, мисалы
std::array<int, factorial(5)>; - массивдин өлчөмү, санагычтын мааниси,
caseбелгиси.
constexpr функциясы туура эмес (диагностика талап кылынбайт). Бирок аткаруу убагындагы аргументтер менен чакырылган туура constexpr функциясы толук калыпта: ал жөн гана аткаруу убагында иштейт.