Ответ 1
Я не знаю никакого общего способа, но знаю два конкретных случая, когда это возможно.
Конкретный случай некоторых компиляторов
Также gcc и clang, который копирует все функции gcc, имеют встроенную функцию __builtin_constant_p
. Я не уверен, будет ли gcc правильно видеть аргумент для встроенной функции как константной, но я боюсь, что вам придется использовать ее из макроса:
#define strlen_smart(s) \
(__builtin_constant_p(s) && __builtin_constant_p(*s) ? \
strlen_constexpr(s) : \
strlen(s))
Может быть полезно. Обратите внимание, что я тестирую как s
, так и *s
для constexpr, потому что указатель на статический буфер является константой времени компиляции, а длина - нет.
Бонус: конкретный случай литералов (не фактический ответ)
Для конкретного набора strlen
вы можете использовать тот факт, что строковые литералы не имеют тип const char *
, а типа const char[N]
, который неявно преобразуется в const char *
. Но он также преобразуется в const char (&)[N]
, а const char *
- нет.
Итак, вы можете определить:
template <size_t N>
constexpr size_t strlen_smart(const char (&array)[N])
(плюс, очевидно, strlen_smart
на const char *
вперед до strlen
)
Я иногда использовал функцию с этим типом аргумента даже в С++ 98 с определением, соответствующим (я не пытался перегрузить strlen
сам, но перегрузки были такими, что я мог бы не называть его):
template <size_t N>
size_t strlen_smart(const char (&)[N]) { return N - 1; }
У этого есть проблема, что для
char buffer[10] = { 0 };
strlen_smart(buffer);
должен сказать 0, но этот оптимизированный вариант просто говорит 9. Функции не имеют смысла вызывать на таких буферах, поэтому мне было все равно.