Подтвердить что ты не робот

Как иметь псевдоним "constexpr и runtime"

Constexpr может быть полезным и полезным для оптимизации компиляции. Например...

strlen(char*)

Может быть предварительно скомпилирован с использованием....

constexpr inline size_t strlen_constexpr(char* baseChar) {
    return (
            ( baseChar[0] == 0 )
            ?(// if {
              0
              )// }
            :(// else {
              strlen_constexpr( baseChar+1 ) + 1 
              )// }
            );
}

Который дает ему время исполнения "0" при оптимизации... Но более 10 + x медленнее во время выполнения

// Test results ran on a 2010 macbook air
--------- strlen ---------
Time took for 100,000 runs:1054us.
Avg Time took for 1 run: 0.01054us.
--------- strlen_constexpr ---------
Time took for 100,000 runs:19098us.
Avg Time took for 1 run: 0.19098us.

Есть ли существующий макрос/шаблон, где вместо него может использоваться одна унифицированная функция. то есть.

constexpr size_t strlen_smart(char* baseChar) {
    #if constexpr
    ... constexpr function
    #else its runtime
    ... runtime function
}

Или какой-то перегрузочный хак, который позволит следующие

constexpr size_t strlen_smart(char* baseChar) {
    ... constexpr function
}

inline size_t strlen_smart(char* baseChar) {
    ... runtime function
}

Примечание: Этот вопрос относится к концепции в целом. Имеет две отдельные функции для среды выполнения и constexpr вместо приведенных здесь примерных функций.

Отказ от ответственности: Настройка компилятора на -O3 (уровень оптимизации) более чем достаточно, чтобы исправить 99,9% статических char оптимизаций, делая все приведенные выше примеры "бессмысленными". Но это не относится к этому вопросу, поскольку оно относится к другим "примерам", а не только к strlen.

4b9b3361

Ответ 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. Функции не имеют смысла вызывать на таких буферах, поэтому мне было все равно.