Учитывая очень тривиальную функцию,
int transform(int val) {
return (val + 7) / 8;
}
Должно быть совершенно очевидно, что эту функцию легко превратить в constexpr
функцию, что позволяет мне использовать ее при определении constexpr
переменных, например:
constexpr int transform(int val) {
return (val + 7) / 8;
}
Мое предположение состоит в том, что это строго улучшение, поскольку функцию все еще можно вызывать вне constexpr
контекста, и теперь ее также можно использовать для определения постоянных переменных во время компиляции.
У меня вопрос, есть ли ситуации, когда это плохая идея? Например, делая эту функцию constexpr
, могу ли я когда-нибудь столкнуться с ситуацией, когда эта функция больше не будет использоваться в определенных обстоятельствах или где она будет плохо себя вести?
Ответы:
Это имеет значение только в том случае, если функция является частью общедоступного интерфейса, и вы хотите, чтобы будущие версии вашего API были бинарно-совместимыми. В этом случае вы должны тщательно продумать, как вы хотите развивать свой API и где вам нужны точки расширения для будущих изменений.
Это делает
constexpr
классификатор безотзывным дизайнерским решением. Вы не можете удалить этот квалификатор без несовместимого изменения вашего API. Это также ограничивает то, как вы можете реализовать эту функцию, например, вы не сможете делать какие-либо записи в этой функции. Не каждая тривиальная функция останется тривиальной в вечности.Это означает, что вы должны предпочтительно использовать
constexpr
функции, которые по своей природе являются чистыми функциями, и это было бы действительно полезно во время компиляции (например, для метапрограммирования шаблонов). Не было бы хорошо делать функции constexpr только потому, что текущая реализация оказывается совместимой с constexpr.Там, где оценка во время компиляции не требуется, использование встроенных функций или функций с внутренней связью может показаться более подходящим
constexpr
. Общим для всех этих вариантов является то, что тело функции является «общедоступным» и доступно в том же модуле компиляции, что и место вызова.Если рассматриваемая функция не является частью стабильного общедоступного API, это не проблема, поскольку вы можете произвольно изменить дизайн по своему желанию. Но поскольку теперь вы контролируете все сайты вызовов, нет необходимости отмечать функцию constexpr «на всякий случай». Вы знаете , используете ли вы эту функцию в контексте constexpr. Добавление излишне ограничительных классификаторов может тогда рассматриваться как запутывание.
источник
Обозначение функции as
constexpr
также делает ее встроенной функцией § [dcl.constexpr] / 1:inline
в свою очередь означает, что вам нужно включить определение этой функции в каждую единицу перевода, в которой она может использоваться. Это в основном означает, чтоconstexpr
функции должны быть либо:Большинство типичных функций, которые вы хотите объявить в заголовке и определить в исходном файле (и все, что использует их, включает в себя только заголовок, а затем ссылки на объектный файл этого источника)
constexpr
просто не будет работать.Теоретически, я полагаю, что вы можете просто переместить все в заголовки и иметь только один исходный файл, который просто включает все заголовки, но это сильно повредит времени компиляции, а для большинства серьезных проектов потребуются огромные объемы памяти для компиляции.
constexpr
Функция также ограничена в некотором роде, так что для некоторых функций , которые она не может быть вариантом вообще. Ограничения включают в себя:constexpr
.try
блок.Я пропустил пару довольно непонятных вещей (например, они также не могут содержать
goto
илиasm
выражение), но вы поняли - для многих вещей это просто не сработает.Итог: да, есть довольно много ситуаций, когда это было бы плохой идеей.
источник