Вопрос

Constexpr can be awsome and useful for compilation optimisation. For example...

strlen(char*)

Can be precompiled using....

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

Which gives it a runtime cost of "0" when optimised... But is more than 10+x slower on runtime

// 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.

Are there any existing macro / template hack where a single unified function can be used instead. ie.

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

Or some overloading hack that would allow the following

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

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

Note: This question applies to the concept in general. Of having 2 separate functions for runtime and constexpr instead of the example functions given.

Disclaimer: Setting the compiler to -O3 (optimization level) is more than enough to fix 99.9% of static char optimizations making all the examples above "pointless". But that's beside the point of this question, as it applies to other "examples", and not just strlen.

Это было полезно?

Решение

I don't know any generic way, but I know two specific cases where it is possible.

Specific case of some compilers

Also gcc, and clang which copies all features of gcc, have a built-in function __builtin_constant_p. I am not sure whether gcc will correctly see argument to inline function as constant, but I fear you'd have to use it from a macro:

#define strlen_smart(s) \
    (__builtin_constant_p(s) && __builtin_constant_p(*s) ? \
        strlen_constexpr(s) : \
        strlen(s))

Might be of use. Note that I am testing both s and *s for constexpr, because pointer to static buffer is a compile time constant while it's length is not.

Bonus: Specific case of literals (not an actual answer)

For the specific cast of strlen you can use the fact that string literals are not of type const char * but of type const char[N] that implicitly converts to const char *. But it also converts to const char (&)[N] as well while const char * does not.

So you can define:

template <size_t N>
constexpr size_t strlen_smart(const char (&array)[N])

(plus obviously strlen_smart on const char * forwards to strlen)

I've sometimes used function with this type of argument even in C++98 with definition corresponding to (I didn't try to overload strlen itself, but the overloads were so I could avoid calling it):

template <size_t N>
size_t strlen_smart(const char (&)[N]) { return N - 1; }

This has the problem that for

char buffer[10] = { 0 };

strlen_smart(buffer);

should say 0, but that optimized variant just says 9. The functions don't make sense to be called on buffers like that so I didn't care.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top