Domanda

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.

È stato utile?

Soluzione

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.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top