55 votes

Pourquoi C ++11 constexpr est-il si restrictif?

Comme vous le savez probablement, C++11 introduit l' constexpr mot-clé.

C++11 introduit le mot-clé constexpr, qui permet à l'utilisateur de garantir qu'une fonction ou le constructeur de l'objet est au moment de la compilation constante. [...] Cela permet au compilateur de comprendre et de vérifier que [nom de la fonction] est un constante de compilation.

Ma question est de savoir pourquoi il y a des restrictions sur la forme des fonctions qui peuvent être déclarés. Je comprends le désir de garantir que la fonction est pur, mais réfléchissez à ceci:

L'utilisation de constexpr sur une fonction impose certaines restrictions sur ce que les cette fonction peut faire. First, the function must have a non-void return type. Second, the function body cannot declare variables or define new types. Third, the body may only contain declarations, null statements and a single return statement. There must exist argument values such that, after argument substitution, the expression in the return statement produces a constant expression.

Cela signifie que cette fonction pure est illégal:

constexpr int maybeInCppC1Y(int a, int b)
{
    if (a>0)
        return a+b;
    else
        return a-b;
  //can be written as   return  (a>0) ? (a+b):(a-b); but that isnt the point
}

Aussi, vous ne pouvez pas définir des variables locales... :( Alors je me demandais est-ce une décision de conception, ou de faire des compilateurs de le sucer quand il s'agit de prouver l'existence de la fonction un est-il pur?

31voto

Flexo Points 39273

Les règles d' constexpr fonctions sont conçues de telle sorte qu'il est impossible d'écrire un constexpr fonction qui a des effets secondaires.

En exigeant constexpr n'ont aucun effets secondaires, il devient impossible pour un utilisateur de déterminer le lieu et le moment où il a été réellement évaluée. Ceci est important car constexpr fonctions sont autorisés à se produire lors de la compilation et de l'exécution, à la discrétion du compilateur.

Si des effets indésirables ont été autorisés alors, il faudrait que certaines règles concernant l'ordre dans lequel ils devraient être observées. Que serait incroyablement difficile à définir - même plus difficile que l' static initialisation du problème de commande.

Relativement simple ensemble de règles pour garantir que ces fonctions soient sans effets secondaires est d'exiger qu'ils soient une seule expression (avec quelques restrictions supplémentaires sur le dessus de cela). Cela semble limiter initialement et les règles de la déclaration if que vous avez noté. Alors que ce cas particulier pourrait avoir aucun effets secondaires, elle aurait introduit supplémentaire de complexité dans les règles, et étant donné que vous pouvez écrire les mêmes choses à l'aide de l'opérateur ternaire ou de manière récursive, c'est vraiment pas une affaire énorme.

n2235 est le papier qui a proposé l' constexpr plus en C++. Il traite de la raison d'être de la conception - la citation qui semble être celui-ci à partir d'une discussion sur les destructeurs, mais généralement:

La raison en est qu'une constante de l'expression est destiné à être évalué par le compilateur au temps de traduction, tout comme toute autre littéral de type intégré; qu'en particulier, aucune observables effet secondaire est autorisée.

Il est intéressant de noter que le document mentionne également qu'une proposition précédente, il est suggéré de le le compilateur déduit automatiquement les fonctions qui ont été constexpr sans le mot clé new, mais cela s'est avéré être unworkably complexe, qui semble à l'appui de ma proposition, que les règles ont été conçues pour être simples.

(Je pense qu'il y aura d'autres citations dans les références citées dans le document, mais qui couvre le point clé de mon argument sur les pas d'effets secondaires)

30voto

Daniel Earwicker Points 63298

La raison pour laquelle vous pourriez avoir besoin d'écrire des déclarations à la place des expressions que vous voulez prendre avantage de les capacités supplémentaires d'états, en particulier la capacité de la boucle. Mais pour être utile, il faudrait que la possibilité de déclarer des variables (aussi interdits).

Si vous combinez une facilité pour la lecture en boucle, avec des variables mutables, avec logique de branchement (comme en if des déclarations), alors vous avez la possibilité de créer des boucles infinies. Il n'est pas possible de déterminer si une telle boucle va jamais se terminer (le problème de l'arrêt). Ainsi, certaines sources serait la cause de la compilateur pour accrocher.

Par récursive à l'aide de fonctions pures, il est possible de provoquer une récursion infinie, ce qui peut être démontré de manière équivalente puissant pour le bouclage les capacités décrites ci-dessus. Cependant, C++ dispose déjà de ce problème au moment de la compilation - il se produit avec le modèle d'extension et ainsi de compilateurs déjà avoir un interrupteur pour le "modèle de la pile de la profondeur" afin qu'ils sachent le moment d'abandonner.

Si les restrictions semblent conçues pour s'assurer que ce problème (qui est de déterminer si une compilation C++ ne sera jamais fini) ne peut pas faire plus épineux que c'est déjà fait.

13voto

hivert Points 7080

En réalité, le comité de normalisation C ++ envisage de supprimer plusieurs de ces contraintes pour c ++14. Voir le document de travail suivant http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2013/n3597.html

3voto

celtschk Points 9699

Les restrictions pourraient certainement être levé un peu, sans activation de code qui ne peut pas être exécuté au cours de la compilation, ou qui ne peut pas être prouvée à toujours arrêter. Cependant, je suppose que ce n'était pas fait parce que

  • il ne ferait que compliquer le compilateur pour un gain minime. Compilateurs C++ sont assez complexes comme

  • en précisant exactement combien est autorisé sans violer les restrictions ci-dessus auraient été beaucoup de temps, et étant donné que les caractéristiques ont été reportées afin d'obtenir la norme de la porte, il y avait peu d'intérêt pour ajouter plus de travail (et de loin retard de la norme) pour peu de gain

  • certaines des restrictions aurait été plutôt arbitraire ou plutôt compliqué (surtout sur les boucles, étant donné que C++ n'est pas le concept d'un natif de l'incrémentation de la boucle for, mais à la fois la condition et l'incrément de code doivent être explicitement spécifiée dans l'instruction for, rendant ainsi possible l'utilisation arbitraire des expressions pour eux)

Bien sûr, seul un membre de la commission des normes pourrait donner une réponse faisant autorité si mes suppositions sont correctes.

-4voto

Abdurrahim Points 9

Je pense que constexpr est juste pour les objets const. Je veux dire, vous pouvez maintenant avoir static const objets comme String::empty_string des constructions de manière statique(sans le piratage!). Cela peut réduire le temps avant que le "principal" appelé. Et static const objets peuvent avoir des fonctions comme .length(), operator==,... donc c'est pourquoi 'expr' est nécessaire. En "C", vous pouvez créer constante statique des structures comme ci-dessous:

static const Foos foo = { .a = 1, .b = 2, };

Le noyau Linux a des tonnes de ce type de classes. En c++, vous pouvez le faire maintenant avec constexpr.

note: je ne sais pas mais le code ci-dessous ne doivent pas être acceptées comme si version:

constexpr int maybeInCppC1Y(int a, int b) { return (a > 0) ? (a + b) : (a - b); }

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