73 votes

Quand une fonction constexpr est-elle évaluée au moment de la compilation ?

Puisqu'il est possible qu'une fonction déclarée comme constexpr puisse être appelée pendant l'exécution, selon quels critères le compilateur décide-t-il de la calculer à la compilation ou pendant l'exécution ?

template<typename base_t, typename expo_t>
constexpr base_t POW(base_t base, expo_t expo)
{
    return (expo != 0 )? base * POW(base, expo -1) : 1;
}

int main(int argc, char** argv)
{
    int i = 0;
    std::cin >> i;

    std::cout << POW(i, 2) << std::endl;
    return 0;
}

Dans ce cas, i est inconnu au moment de la compilation, ce qui est probablement la raison pour laquelle le compilateur traite POW() comme une fonction régulière qui est appelée au moment de l'exécution. Cependant, cette dynamique, aussi pratique qu'elle puisse paraître, a quelques implications peu pratiques. Par exemple, pourrait-il y avoir un cas où je voudrais que le compilateur calcule une fonction constexpr pendant la compilation, où le compilateur décide de la traiter comme une fonction normale à la place, alors que cela aurait également fonctionné pendant la compilation ? Existe-t-il des pièges courants connus ?

109voto

K-ballo Points 44794

constexpr fonctions sera est évaluée au moment de la compilation lorsque tous ses arguments sont des expressions constantes et que le résultat est également utilisé dans une expression constante. Une expression constante peut être un littéral (comme 42 ), un argument de modèle non-type (comme N sur template<class T, size_t N> class array; ), un enum (comme Blue sur enum Color { Red, Blue, Green }; une autre variable déclarée constexpr et ainsi de suite.

Ils pourrait est évalué lorsque tous ses arguments sont des expressions constantes et que le résultat est no utilisé dans une expression constante, mais cela dépend de l'implémentation.

24voto

Pubby Points 29386

La fonction doit être évaluée au moment de la compilation lorsqu'une expression constante est nécessaire.

La méthode la plus simple pour garantir cela est d'utiliser un fichier de type constexpr ou std::integral_constant :

constexpr auto result = POW(i, 2); // this should not compile since i is not a constant expression
std::cout << result << std::endl;

o:

std::cout << std::integral_constant<int, POW(i, 2)>::value << std::endl;

o

#define POW_C(base, power) (std::integral_constant<decltype(POW((base), (power)), POW((base), (power))>::value)

std::cout << POW_C(63, 2) << std::endl;

o

template<int base, int power>
struct POW_C {
  static constexpr int value = POW(base, power);
};

std::cout << POW_C<2, 63>::value << std::endl;

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