La formulation est en fait le sujet de rapport de défaut #1313 qui dit:
Les exigences pour les expressions constantes ne sont pas actuellement, mais devrait exclure les expressions qui ont un comportement indéfini, comme l'arithmétique des pointeurs quand les liens ne pointent pas vers des éléments de la même matrice.
La résolution de la formulation actuelle que nous avons maintenant, donc, de toute évidence, cela a été prévu, afin de quels outils est-ce à nous donner?
Nous allons voir ce qui se passe lorsque nous essayons de créer un constexpr variable avec une expression qui contient un comportement indéfini, nous utiliserons clang
pour tous les exemples suivants. Ce code (voir en direct):
constexpr int x = std::numeric_limits<int>::max() + 1 ;
génère l'erreur suivante:
error: constexpr variable 'x' must be initialized by a constant expression
constexpr int x = std::numeric_limits<int>::max() + 1 ;
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
note: value 2147483648 is outside the range of representable values of type 'int'
constexpr int x = std::numeric_limits<int>::max() + 1 ;
^
Ce code (voir en direct):
constexpr int x = 1 << 33 ; // Assuming 32-bit int
produit cette erreur:
error: constexpr variable 'x' must be initialized by a constant expression
constexpr int x = 1 << 33 ; // Assuming 32-bit int
^ ~~~~~~~
note: shift count 33 >= width of type 'int' (32 bits)
constexpr int x = 1 << 33 ; // Assuming 32-bit int
^
et ce code qui a un comportement indéfini dans un constexpr fonction:
constexpr const char *str = "Hello World" ;
constexpr char access( int index )
{
return str[index] ;
}
int main()
{
constexpr char ch = access( 20 ) ;
}
produit cette erreur:
error: constexpr variable 'ch' must be initialized by a constant expression
constexpr char ch = access( 20 ) ;
^ ~~~~~~~~~~~~
note: cannot refer to element 20 of array of 12 elements in a constant expression
return str[index] ;
^
Eh bien, c'est utile, le compilateur peut détecter un comportement indéfini dans constexpr, ou au moins ce qu' clang
croit est pas défini. Remarque, gcc
se comporte de la même, sauf dans le cas d'un comportement indéfini à droite et à gauche maj, gcc
se produisent généralement un avertissement dans ces cas, mais il voit encore l'expression de la constante.
Nous pouvons utiliser cette fonctionnalité via SFINAE pour détecter si un ajout de l'expression serait de provoquer un débordement, le inventée suivant l'exemple a été inspiré par la dpj est intelligent de réponse ici:
#include <iostream>
#include <limits>
template <typename T1, typename T2>
struct addIsDefined
{
template <T1 t1, T2 t2>
static constexpr bool isDefined()
{
return isDefinedHelper<t1,t2>(0) ;
}
template <T1 t1, T2 t2, decltype( t1 + t2 ) result = t1+t2>
static constexpr bool isDefinedHelper(int)
{
return true ;
}
template <T1 t1, T2 t2>
static constexpr bool isDefinedHelper(...)
{
return false ;
}
};
int main()
{
std::cout << std::boolalpha <<
addIsDefined<int,int>::isDefined<10,10>() << std::endl ;
std::cout << std::boolalpha <<
addIsDefined<int,int>::isDefined<std::numeric_limits<int>::max(),1>() << std::endl ;
std::cout << std::boolalpha <<
addIsDefined<unsigned int,unsigned int>::isDefined<std::numeric_limits<unsigned int>::max(),std::numeric_limits<unsigned int>::max()>() << std::endl ;
}
ce qui donne (voir en direct):
true
false
true
Il n'est pas évident que la norme exige que ce comportement, mais apparemment ce commentaire par Howard Hinnant indique qu'il est en effet:
[...] et est également constexpr, sens UB est pris au moment de la compilation
Mise à jour
En quelque sorte j'ai raté Problème de 695 au moment de la Compilation des erreurs de calcul dans constexpr fonctions qui tourne sur le libellé de la section 5
le paragraphe 4 qui avait l'habitude de dire (c'est moi qui souligne à l'avenir):
Si, lors de l'évaluation d'une expression, le résultat n'est pas définie mathématiquement ou pas dans la gamme des représentable valeurs pour son type, le comportement est indéfini, à moins que cette expression apparaît à l'endroit où intégrante expression constante est nécessaire (5.19 [expr.const]), auquel cas le programme est mal formé.
et il ajoute:
conçu comme un Standardese circumlocution pour "évalué au moment de la compilation," un concept qui n'est pas directement définie par la Norme. Il n'est pas clair que cette formulation couvre adéquatement constexpr fonctions.
et plus tard la note dit:
[...]Il y a une tension entre la volonté d'diagnostiquer des erreurs lors de la compilation du temps et de ne pas diagnostiquer des erreurs qui ne sont pas réellement se produire lors de l'exécution.[...]Le consensus de la GTC est qu'une expression comme 1/0 devrait tout simplement être considéré comme non-constante; diagnostic résulterait de l'utilisation de l'expression dans un contexte nécessitant une expression constante.
qui, si je lis correctement confirme l'intention était d'être en mesure de diagnostiquer un comportement non défini au moment de la compilation dans le contexte nécessitant une expression constante.
Nous ne pouvons certainement dire que c'était l'intention, mais il ne suggère fortement qu'il était. La différence dans la façon dont clang
et gcc
traiter undefined quarts ne laisser de place pour le doute.