Há uma propriedade muito elegante de expressões constantes em C ++: sua avaliação não pode ter um comportamento indefinido ( 7.7.4.7 ):
Uma expressão e é uma expressão constante do núcleo, a menos que a avaliação de e, seguindo as regras da máquina abstrata ([intro.execution]), avalie um dos seguintes:
...
uma operação que teria um comportamento indefinido, conforme especificado em [introdução] a [cpp] deste documento [Nota: incluindo, por exemplo, estouro de número inteiro assinado ([expr.prop]), certa aritmética de ponteiro ([expr.add]), divisão por zero ou certas operações de turno - nota final];
Tentar armazenar o valor de 13!
em de constexpr int
fato gera um bom erro de compilação :
constexpr int f(int n)
{
int r = n--;
for (; n > 1; --n) r *= n;
return r;
}
int main()
{
constexpr int x = f(13);
return x;
}
Resultado:
9:19: error: constexpr variable 'x' must be initialized by a constant expression
constexpr int x = f(13);
^ ~~~~~
4:26: note: value 3113510400 is outside the range of representable values of type 'int'
for (; n > 1; --n) r *= n;
^
9:23: note: in call to 'f(3)'
constexpr int x = f(13);
^
1 error generated.
(Por que o erro diz "ligar para 'f (3)'", enquanto é uma ligação para f (13)? ..)
Então, eu remover constexpr
a partir x
, mas fazer f
um consteval
. De acordo com os documentos :
consteval - especifica que uma função é uma função imediata, ou seja, toda chamada para a função deve produzir uma constante em tempo de compilação
Espero que esse programa cause novamente um erro de compilação. Mas, em vez disso, o programa compila e executa com o UB .
Por que é que?
UPD: os comentaristas sugeriram que este é um bug do compilador. Eu relatei: https://bugs.llvm.org/show_bug.cgi?id=43714
in call to 'f(3)'
- isto é estranho! Ex. Se você colocarf(123)
clang adverte sobrein call to 'f(119)'
.