std::max() et std::min() pas constexpr
je viens de remarquer que la nouvelle norme définit min(a,b)
et max(a,b)
sans constexpr
.
exemples de 25.4.7, [alg.min.max]:
template<class T> const T& min(const T& a, const T& b);
template<class T> T min(initializer_list<T> t);
N'est-ce pas dommage? J'aurais aimé écrire
char data[ max(sizeof(A),sizeof(B)) ];
au lieu de
char data[ sizeof(A) > sizeof(B) ? sizeof(A) : sizeof(B) ];
char data[ MAX(sizeof(A),sizeof(B)) ]; // using a macro
pourquoi ces ne peuvent pas être constexpr
?
5 réponses
Mise À Jour Critique
l'analyse ci-dessous est erronée, car elle confond une chose importante . La déclaration suivante, je l'ai fait manquer un détail important, qui exige une réponse entièrement différente.
la référence anonyme
max
renvoie à cet opérande.
le problème ici est que fonction invocation substitution est fait à ce point. Si l'invocation susbstitution incluait la valeur de la conversion de la valeur de la valeur sur cette valeur glissante que max
donne, tout irait bien, parce que la lecture d'une valeur qui se réfère à une durée de stockage temporaire non statique est très bien lors du calcul de l'expression constante . Mais puisque la lecture se produit en dehors de la fonction invocation substitution, le résultat de la fonction invocation la substitution est une valeur l . Le texte respectif du spec dit
une expression constante de référence est une expression constante lvalue core qui désigne un objet avec une durée de stockage statique ou une fonction.
mais la référence que max
renvoie donne une valeur L qui désigne un objet d'une durée de stockage indéterminée. La substitution de l'invocation de la fonction est nécessaire pour produire un constante de l'expression , pas simplement un de base expression constante. Donc max(sizeof(A), sizeof(B))
n'est pas garanti.
le texte suivant (ancien) doit être lu en tenant compte de ce qui précède .
Je ne vois pas pourquoi vous ne voudriez pas y coller un constexpr
. Quoi qu'il en soit, le code suivant est certainement utile
template<typename T> constexpr
T const& max(T const& a, T const& b) {
return a > b ? a : b;
}
contrairement à ce que d'autres réponses écrivent, je pense que c'est légal. Toutes les instanciations de max
ne sont pas nécessairement des fonctions constexpr. La n3242 actuelle dit
si la spécialisation instanciée d'un modèle de fonction de constexpr ou d'une fonction de membre d'un modèle de classe ne répond pas aux exigences d'une fonction de constexpr ou d'un constructeur de constexpr, cette spécialisation n'est pas un constexpr fonction ou constexpr constructeur.
si vous appelez le modèle, la déduction d'argument donnera une spécialisation de modèle de fonction. L'appeler déclenchera substitution d'invocation de fonction . Considérez l'appel suivant
int a[max(sizeof(A), sizeof(B))];
il va d'abord faire une conversion implicite des deux valeurs size_t
PR aux deux paramètres de référence, liant les deux références à des objets temporaires stockant leur valeur. Le résultat de cette conversion est un glvalue pour chaque cas qui se réfère à un objet temporaire (voir 4p3). Maintenant la substitution d'invocation de fonction prend ces deux glvalues et substitue toutes les occurences de a
et b
dans le corps de fonction par ces glvalues
return (<glval.a>) > (<glval.b>) ? (<glval.a>) : (<glval.b>);
la condition exigera des conversions lvalue à rvalue sur ces valeurs GLG, qui sont autorisées par 5.1519210920"
- une valeur de type littéral qui se réfère à un objet temporaire non volatil initialisé avec une expression constante
l'expression conditionnelle donnera une valeur GLG au Premier ou au second opérande. La référence anonyme max
renvoie à cet opérande. Et la conversion finale lvalue to rvalue se produisant dans la spécification de la dimension du tableau sera valide par la même règle citée ci-dessus.
notez que initializer_list
n'a actuellement pas constexpr
fonctions de membre. Il s'agit d'une limitation connue et sera traitée post-C++0x, faisant très probablement ces membres constexpr
.
std::min et std::max sont constexpr en C++14, ce qui signifie évidemment il n'y a pas une bonne raison (de nos jours) de ne pas les avoir constexpr. Problème résolu: -)
l'inclusion des versions constexpr
de std::min()
et std::max()
dans C++14 démontre qu'il n'y a aucun obstacle fondamental à faire (versions de) ces fonctions constexpr
. Il semble que cela n'ait pas été envisagé assez tôt lorsque constexpr
a été ajouté à C++11.
évidemment, pour les versions dans lesquelles une fonction de comparaison est fournie, cette fonction doit elle-même être constexpr
pour que l'extension du modèle réussisse.
min
et max
ne sont que des expressions constantes si vous les appelez, avec des expressions constantes comme arguments. Comme ils sont censés être beaucoup plus utilisables que ça, vous ne pouvez pas faire la déclaration.
voici ce que Wikipedia dit à propos de constexpr
(c'est nous qui soulignons). Je sais que Wikipédia n'est pas la référence ultime, mais je crois que c'est correct dans ce cas.
L'utilisation de
constexpr
sur une fonction impose des limites très strictes ce que cette fonction peut faire. Tout d'abord, l' la fonction doit avoir un retour non nul type. Deuxièmement, le contenu de la fonction doit être du formulaire: return expr. Troisièmement, l'expr doit être une constante expression, après argument substitution. Cette expression constante ne peut appeler d'autres fonctions définies comme constexpr, ou il peut utiliser d'autres variables de données à expression constante.
Ma conjecture est que, dans le cas général, l'opérateur<(T, T) n'est pas garantie constexpr.