Чи коли-небудь погано відзначати конспект функції C ++?


26

Враховуючи дуже тривіальну функцію,

int transform(int val) {
    return (val + 7) / 8;
}

Це повинно бути дуже очевидним, що легко перетворити цю функцію на constexprфункцію, що дозволяє мені використовувати її під час визначення constexprзмінних, наприклад:

constexpr int transform(int val) {
    return (val + 7) / 8;
}

Моє припущення полягає в тому, що це суто вдосконалення, оскільки функцію все ще можна викликати в неконтексті constexpr, і тепер вона також може бути використана для визначення постійних змінних часу компіляції.

Моє запитання: чи існують ситуації, коли це погана ідея? Мовляв, виконуючи цю функцію constexpr, чи можу я колись зіткнутися з ситуацією, коли ця функція вже не може бути використана в певних обставинах, або де вона буде погано поводитися?


1
Єдине, про що я міг придумати, - це помилки компілятора. Можливо, що рекурсивний виклик функції constexpr може викликати дійсно повільний крок компіляції або навіть компілятор поза збоєм пам'яті.
Zan Lynx

Відповіді:


19

Це має значення лише в тому випадку, якщо функція є частиною загальнодоступного інтерфейсу, і ви хочете зберегти майбутні версії API, бінарні сумісні. У такому випадку вам потрібно добре подумати, як ви хочете розвивати свій API і де вам потрібні точки розширення для подальших змін.

Це робить constexprкласифікатор безповоротним дизайнерським рішенням. Ви не можете видалити цей класифікатор без несумісної зміни в API. Він також обмежує те, як ви можете реалізувати цю функцію, наприклад, ви не зможете робити жодного журналу в межах цієї функції. Не кожна тривіальна функція залишиться тривіальною у вічності.

Це означає, що бажано використовувати constexprдля функцій, які по суті є чистими функціями, і це було б корисно під час компіляції (наприклад, для метапрограмування шаблонів). Було б непогано робити функції constexpr лише тому, що поточна реалізація, можливо, сумісна з contexpr.

Якщо оцінка часу компіляції не є необхідною, більш правильним буде здаватися використання вбудованих функцій або функцій із внутрішнім зв’язком constexpr. Усі ці варіанти мають спільне те, що тіло функції є "загальнодоступним" та доступне в тому ж блоці компіляції, що і місце розташування виклику.

Якщо функція, про яку йдеться, не входить у стабільний, публічний API, це менше проблеми, оскільки ви можете довільно змінювати дизайн за бажанням. Але оскільки ви зараз контролюєте всі сайти викликів, не потрібно позначати функцію constexpr "про всяк випадок". Ви знаєте, чи використовуєте ви цю функцію в контексті constexpr. Додавання зайвих обмежувальних класифікаторів може вважатися затемненням.


12

Позначення функції як constexprтакож робить її вбудованою функцією § [dcl.constexpr] / 1:

Функція або статичний член даних, оголошений специфікатором constexpr, неявно є вбудованою функцією або змінною (7.1.6).

inline, у свою чергу, означає, що вам потрібно включити визначення цієї функції у кожну одиницю перекладу, в якій вона може використовуватися. Це в основному означає, що constexprфункції повинні бути або:

  1. обмежений для використання в одному блоці перекладу, або
  2. визначені в заголовку.

Більшість типових функцій, які ви хочете оголосити в заголовку та визначити у вихідному файлі (і все, що їх використовує, включає лише заголовок, а потім посилання на об’єктний файл цього джерела) constexprпросто не працюватиме.

Теоретично я гадаю, що ви можете просто перемістити все в заголовки і мати лише один вихідний файл, який включає лише всі заголовки, але це зашкодить час складання різко, і для більшості серйозних проектів потрібно буде скласти величезну кількість пам'яті.

constexprФункція також обмежена в деякому роді, так що для деяких функцій , які вона не може бути варіантом взагалі. Обмеження включають:

  1. віртуальних функцій бути не може constexpr.
  2. його тип повернення повинен бути "буквальним типом" (наприклад, жодних об'єктів, що не мають тривальних ctors або dtors).
  3. всі його параметри повинні бути буквальними типами.
  4. функціональний орган не може містити tryблок.
  5. воно не може містити змінне визначення нелітерального типу або що-небудь зі статичним або потоковим зберіганням.

Я пропустив декілька досить незрозумілих речей (наприклад, він також не може містити gotoані asmзаяву), але ви розумієте, що для кількох речей це просто не вийде.

Підсумок: так, існує досить багато ситуацій, коли це було б поганою ідеєю.


"це не повинно бути віртуальним (до C ++ 20)" Мене цікавить, як віртуальна функція може бути constexpr? Що роблять компілятори?
хаос
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.