Вступ
constexpr
не було введено як спосіб сказати реалізації, що щось можна оцінити в контексті, який вимагає постійного вираження ; відповідні реалізації змогли довести це до C ++ 11.
Щось реалізація не може довести, це наміри певного коду:
- Що розробник хоче висловити з цією суттю?
- Чи слід ми сліпо дозволяти використовувати код у константному виразі , лише тому, що він працює?
Яким був би світ constexpr
?
Скажімо, ви розробляєте бібліотеку і розумієте, що хочете мати можливість обчислити суму кожного цілого числа в проміжку (0,N]
.
int f (int n) {
return n > 0 ? n + f (n-1) : n;
}
Відсутність наміру
Компілятор може легко довести, що вищенаведена функція може бути викликана в постійному виразі якщо переданий аргумент відомий під час перекладу; але ви не заявили про це як про наміри - це просто так сталося.
Тепер хтось інший приходить разом, читає вашу функцію, робить той же аналіз, що і компілятор; " О, ця функція може бути використана в постійному виразі!" , і пише наступний фрагмент коду.
T arr[f(10)]; // freakin' magic
Оптимізація
Ви, як "дивовижний" розробник бібліотеки, вирішите, що f
слід кешувати результат при виклику; хто хотів би обчислювати один і той же набір значень знову і знову?
int func (int n) {
static std::map<int, int> _cached;
if (_cached.find (n) == _cached.end ())
_cached[n] = n > 0 ? n + func (n-1) : n;
return _cached[n];
}
Результат
Ввівши свою нерозумну оптимізацію, ви просто порушили кожне використання своєї функції, що трапилося в контексті, коли константа-вираз .
Ви ніколи не обіцяли, що функція може бути використана в постійному вираженні , і без неї constexpr
не було б можливості надати таку обіцянку.
Отже, навіщо нам це потрібно constexpr
?
Основне використання constexpr - це оголошення намірів .
Якщо сутність не позначена як constexpr
- вона ніколи не передбачалася використовувати в постійному виразі ; і навіть якщо це так, ми покладаємось на компілятора, щоб діагностувати такий контекст (тому що він нехтує нашими намірами).
constexpr
? Якщо так, я можу побачити використання.