21 votes

Comment avoir un alias "constexpr et runtime" ?

Constexpr peut être génial et utile pour l'optimisation de la compilation. Par exemple...

strlen(char*)

Peut être précompilé en utilisant....

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

Ce qui lui donne un coût d'exécution de "0" lorsqu'il est optimisé... Mais il est plus de 10 fois plus lent à l'exécution.

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

Existe-t-il des macros / modèles existants pour lesquels une seule fonction unifiée peut être utilisée à la place, par exemple.

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

Ou un hack de surcharge qui permettrait ce qui suit

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

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

Nota: Cette question s'applique au concept en général. Il s'agit d'avoir deux fonctions distinctes pour runtime et constexpr au lieu des fonctions données en exemple.

Avis de non-responsabilité : Le réglage du compilateur sur -O3 (niveau d'optimisation) est plus que suffisant pour corriger 99,9 % des optimisations des chars statiques, ce qui rend tous les exemples ci-dessus "inutiles". Mais cela n'a rien à voir avec cette question, car elle s'applique à d'autres "exemples", et pas seulement à l'exemple suivant strlen .

10voto

Jan Hudec Points 27417

Je ne connais pas de méthode générique, mais je connais deux cas spécifiques où c'est possible.

Cas spécifique de certains compilateurs

Aussi, gcc, et clang qui copie toutes les fonctionnalités de gcc, ont une fonction intégrée __builtin_constant_p . Je ne suis pas sûr que gcc considère correctement l'argument de la fonction inline comme une constante, mais je crains que vous deviez l'utiliser à partir d'une macro :

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

Ça pourrait être utile. Notez que je teste à la fois s y *s pour constexpr, car le pointeur vers le tampon statique est une constante de compilation alors que sa longueur est no .

Bonus : Cas spécifique des littéraux (pas une réponse réelle)

Pour le casting spécifique de strlen vous pouvez utiliser le fait que les littéraux des chaînes de caractères sont no de type const char * mais de type const char[N] qui se convertit implicitement en const char * . Mais il se convertit aussi en const char (&)[N] ainsi que pendant que const char * ne le fait pas.

Donc vous pouvez définir :

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

(plus évidemment strlen_smart sur const char * en avant vers strlen )

J'ai parfois utilisé une fonction avec ce type d'argument, même en C++98 avec une définition correspondant à (je n'ai pas essayé de surcharger) strlen lui-même, mais les surcharges étaient pour que je puisse éviter de l'appeler) :

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

Cela pose le problème suivant : pour

char buffer[10] = { 0 };

strlen_smart(buffer);

devrait dire 0, mais cette variante optimisée dit juste 9. Les fonctions n'ont pas de sens pour être appelées sur des tampons comme ça, donc je ne m'en suis pas soucié.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X