Dada uma função muito trivial,
int transform(int val) {
return (val + 7) / 8;
}
Deveria ser muito óbvio que é fácil transformar essa função em uma constexpr
função, permitindo que eu a use ao definir constexpr
variáveis, assim:
constexpr int transform(int val) {
return (val + 7) / 8;
}
Minha suposição é que isso é estritamente uma melhoria, já que a função ainda pode ser chamada em um constexpr
contexto fora do contexto, e agora também pode ser usada para ajudar a definir variáveis constantes em tempo de compilação.
Minha pergunta é : existem situações em que essa é uma má ideia? Como, ao fazer essa função constexpr
, posso encontrar uma situação em que essa função não será mais utilizável em uma circunstância específica ou onde ela se comportará mal?
Respostas:
Isso importa apenas se a função fizer parte de uma interface pública e você desejar manter versões futuras da sua API compatível com binários. Nesse caso, você deve pensar cuidadosamente em como deseja evoluir sua API e onde precisa de pontos de extensão para futuras alterações.
Isso faz um
constexpr
qualificador uma decisão irrevogável de design. Você não pode remover este qualificador sem uma alteração incompatível na sua API. Também limita como você pode implementar essa função, por exemplo, você não seria capaz de fazer nenhum log dentro dessa função. Nem toda função trivial permanecerá trivial na eternidade.Isso significa que você deve preferencialmente usar
constexpr
para funções que são inerentemente puras e que seriam realmente úteis em tempo de compilação (por exemplo, para metaprogramação de modelos). Não seria bom tornar as funções constexpr apenas porque a implementação atual é passível de ser constexprable.Onde a avaliação em tempo de compilação não é necessária, o uso de funções em linha ou funções com ligação interna parece mais apropriado
constexpr
. Todas essas variantes têm em comum que o corpo da função é "público" e está disponível na mesma unidade de compilação que o local da chamada.Se a função em questão não fizer parte de uma API pública estável, isso é um problema menor, pois você pode alterar arbitrariamente o design à vontade. Mas como agora você controla todos os sites de chamada, não é necessário marcar uma função constexpr "apenas por precaução". Você sabe se está usando esta função em um contexto constexpr. Adicionar qualificadores desnecessariamente restritivos pode ser considerado ofuscamento.
fonte
Marcar uma função como
constexpr
também a torna uma função embutida § [dcl.constexpr] / 1:inline
, por sua vez, significa que você precisa incluir a definição dessa função em todas as unidades de tradução nas quais ela pode ser usada. Isso basicamente significa que asconstexpr
funções devem ser:As funções mais comuns que você deseja declarar em um cabeçalho e definir em um arquivo de origem (e qualquer outra coisa que as use apenas inclui o cabeçalho e, em seguida, os links no arquivo de objeto dessa fonte)
constexpr
simplesmente não funcionam.Em teoria, suponho que você possa simplesmente mover tudo para os cabeçalhos e ter apenas um arquivo de origem que inclua todos os cabeçalhos, mas isso prejudicaria drasticamente o tempo de compilação e, para os projetos mais sérios, seria necessária uma quantidade imensa de memória para compilar.
Uma
constexpr
função também é restrita em alguns aspectos, portanto, para algumas funções, pode não ser uma opção. As restrições incluem:constexpr
.try
bloco.Eu pulei algumas coisas obscuras (por exemplo, ela também não pode conter uma
goto
ou umaasm
declaração), mas você entendeu - para algumas coisas, simplesmente não vai funcionar.Conclusão: sim, existem algumas situações em que isso seria uma péssima idéia.
fonte