latest - g++ c++ 20



É uma extensão do compilador em conformidade para tratar funções de biblioteca padrão não constexpr como constexpr? (1)

gcc compila o seguinte código sem aviso:

#include <cmath>

struct foo {
  static constexpr double a = std::cos(3.);
  static constexpr double c = std::exp(3.);
  static constexpr double d = std::log(3.);
  static constexpr double e1 = std::asin(1.);
  static constexpr double h = std::sqrt(.1);
  static constexpr double p = std::pow(1.3,-0.75);
};

int main()
{
}

Nenhuma das funções de biblioteca padrão usadas acima são funções constexpr , é permitido usá-las onde é necessária uma expressão constante do rascunho do padrão C ++ 11 e do rascunho da seção do padrão C ++ 14 7.1.5 [dcl.constexpr] :

[...] Se for inicializada por uma chamada de construtor, essa chamada deverá ser uma expressão constante (5.19). Caso contrário, ou se um especificador constexpr for usado em uma declaração de referência, toda expressão completa que aparecer em seu inicializador deverá ser uma expressão constante.

Mesmo ao usar -std=c++14 -pedantic ou -std=c++11 -pedantic nenhum aviso é gerado ( veja ao vivo ). O uso de -fno-builtin produz erros ( veja ao vivo ), o que indica que a versão builtin dessas funções de biblioteca padrão estão sendo tratadas como se elas fossem executadas.

Enquanto clang não permite o código com nenhuma combinação de sinalizadores que tentei.

Portanto, esta é uma extensão do gcc para tratar pelo menos algumas funções internas, como se fossem funções consexpr, mesmo que o padrão não exija explicitamente que sejam. Eu esperava pelo menos receber um aviso no modo estrito de conformidade, isso é uma extensão compatível?

https://src-bin.com


Answer #1

TL; DR

No C ++ 14, isso não é explicitamente permitido, embora em 2011 parecesse que este caso seria explicitamente permitido. Não está claro se, para o C ++ 11, isso se enquadra na regra de “como se” , não acredito, pois altera o comportamento observável, mas esse ponto não foi esclarecido na questão a que me refiro abaixo.

Detalhes

A resposta a esta pergunta mudou com o status em evolução da edição de LWG 2013, que começa com:

Suponha que uma função específica não seja marcada como constexpr no padrão, mas que, em alguma implementação específica, é possível escrevê-la dentro das restrições constexpr. Se um implementador marcar uma função como constexpr, isso é uma violação do padrão ou é uma extensão compatível?

No C ++ 11, não estava claro se a regra como se permitia isso, mas a proposta original permitiria explicitamente assim que fosse aceita e podemos ver abaixo no relatório de bug do gcc que eu refiro, essa foi a suposição feita pelo gcc equipe.

O consenso para permitir isso mudou em 2012 e a proposta mudou e, em C ++ 14, essa é uma extensão não conforme. Isso se reflete no rascunho da seção padrão C ++ 14 17.6.5.6 [constexpr.functions] que diz:

[...] Uma implementação não deve declarar nenhuma assinatura de função de biblioteca padrão como constexpr, exceto naquelas em que é explicitamente necessária.

e embora uma leitura estrita disso pareça deixar algum espaço de manobra para tratar implicitamente um construído como se fosse um consprés, podemos ver na citação a seguir na questão que a intenção era evitar divergências nas implementações, pois códigos idênticos poderiam produzir comportamentos diferentes ao usar SFINAE ( ênfase minha ):

Alguma preocupação expressa quando apresentada ao comitê completo pelo voto no status de WP de que esse problema havia sido resolvido sem pensar nas conseqüências para implementações divergentes de bibliotecas, pois os usuários podem usar o SFINAE para observar um comportamento diferente do código idêntico .

Podemos ver no relatório de erros do GCC [C ++ 0x] sinh vs asinh vs constexpr que a equipe confiou na resolução proposta anteriormente do LWG 2013, que diz:

[...] Além disso, uma implementação pode declarar qualquer função como constexpr se a definição dessa função satisfizer as restrições necessárias.

ao decidir se essa alteração nas funções matemáticas foi permitida no modo de conformidade estrita.

Tanto quanto posso dizer, isso se tornaria conforme se -std=c++11 -pedantic um aviso no modo estrito de conformidade, ou seja, usando -std=c++11 -pedantic ou se ele fosse desativado nesse modo.

Observe que adicionei um comentário ao relatório de erros, explicando que a resolução foi alterada desde que o problema foi resolvido originalmente.

Jonathan Wakely apontou em outra pergunta uma discussion mais recente e parece provável que o relatório de bug do gcc seja reaberto para resolver esse problema de conformidade.

E quanto aos intrínsecos

As intrínsecas do compilador não são cobertas pelo padrão e, pelo que sei, elas devem estar isentas desta regra, portanto, usando:

static constexpr double a = __builtin_cos(3.);

deveria ser permitido. Esta pergunta surgiu no relatório de erros e a opinião de Daniel Krügler foi:

[...] As funções da biblioteca e outras intrínsecas provavelmente podem ser consideradas exceções, porque elas não precisam ser "explicáveis" pelas regras da linguagem normal.