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 ?

31
demandé sur Jeffrey Bosboom 2011-04-09 16:54:00

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 .

13
répondu Johannes Schaub - litb 2011-12-27 16:06:12

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: -)

13
répondu einpoklum 2016-03-07 17:48:02

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.

1
répondu Toby Speight 2016-07-14 08:11:22

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.

-1
répondu Mark Ransom 2011-04-09 14:33:11

Ma conjecture est que, dans le cas général, l'opérateur<(T, T) n'est pas garantie constexpr.

-3
répondu ZeRemz 2011-04-09 13:01:55