#include <iostream>
#include <cmath>
/* Intentionally incorrect abs() which seems to override std::abs() */
int abs(int a) {
return a > 0? -a : a;
}
int main() {
int a = abs(-5);
int b = std::abs(-5);
std::cout<< a << std::endl << b << std::endl;
return 0;
}
Eu esperava que a saída fosse -5
e 5
, mas a saída é -5
e -5
.
Eu me pergunto por que esse caso vai acontecer?
Tem alguma coisa a ver com o uso de std
ou o quê?
abs
está incorreta.abs
afetastd::abs()
.5
e5
com clang-5
e-5
com gcc.return 0
- isso teria evitado que as pessoas pensassem que você implementou a função incorretamente sem querer e tornado o comportamento desejado e real mais claro.Respostas:
A especificação da linguagem permite que as implementações sejam implementadas
<cmath>
declarando (e definindo) as funções padrão no namespace global e, em seguida, trazendo-as para o namespacestd
por meio de declarações de uso. Não é especificado se esta abordagem é usadaAparentemente, você está lidando com uma das implementações que decidiu seguir essa abordagem (por exemplo, GCC). Ou seja, sua implementação fornece
::abs
, enquantostd::abs
simplesmente "se refere" a::abs
.Uma questão que permanece neste caso é por que, além do padrão,
::abs
você foi capaz de declarar o seu próprio::abs
, ou seja, por que não há erro de definição múltipla. Isso pode ser causado por outro recurso fornecido por algumas implementações (por exemplo, GCC): eles declaram funções padrão como os chamados símbolos fracos , permitindo assim que você "substitua" por suas próprias definições.Esses dois fatores juntos criam o efeito que você observa: a substituição do símbolo fraco de
::abs
também resulta na substituição destd::abs
. O quão bem isso está de acordo com o padrão da linguagem é uma história diferente ... Em qualquer caso, não confie neste comportamento - não é garantido pela linguagem.No GCC, esse comportamento pode ser reproduzido pelo seguinte exemplo minimalista. Um arquivo de origem
Outro arquivo fonte
Nesse caso, você também observará que a nova definição de
::foo
("Goodbye!"
) no segundo arquivo de origem também afeta o comportamento deN::foo
. Ambas as chamadas serão geradas"Goodbye!"
. E se você remover a definição de::foo
do segundo arquivo de origem, ambas as chamadas serão enviadas para a definição "original" de::foo
e para a saída"Hello!"
.A permissão dada pelo 20.5.1.2/4 acima existe para simplificar a implementação do
<cmath>
. As implementações podem simplesmente incluir o estilo C<math.h>
, depois declarar novamente as funçõesstd
e adicionar algumas adições e ajustes específicos de C ++. Se a explicação acima descreve adequadamente a mecânica interna do problema, a maior parte dela depende da capacidade de substituição de símbolos fracos para versões de estilo C das funções.Observe que se nós simplesmente substituirmos globalmente
int
pordouble
no programa acima, o código (sob GCC) se comportará "como esperado" - ele será impresso-5 5
. Isso acontece porque a biblioteca padrão C não temabs(double)
função. Ao declarar o nossoabs(double)
, não substituímos nada.Mas se depois de alternar de
int
comdouble
também mudarmos deabs
parafabs
, o comportamento estranho original reaparecerá em toda sua glória (saída-5 -5
).Isso é consistente com a explicação acima.
fonte
using ::abs;
como para o,using ::asin;
portanto, você pode sobrescrever a declaração, outro ponto a ser mencionado é que as funções definidas no namespace std não são declaradas para int, mas sim para double , float#include<cmath>
do meu código, obtive a mesma resposta. »abs
pode ser declarado em<cstdlib>
, o que pode ser incluído implicitamente por meio de<iostream>
. Tente remover o seu próprioabs
e ver se ele ainda compila.Seu código causa comportamento indefinido.
C ++ 17 [extern.names] / 4:
Portanto, você não pode fazer uma função com o mesmo protótipo da biblioteca C padrão
int abs(int);
. Independentemente de quais cabeçalhos você realmente inclui ou se esses cabeçalhos também colocam nomes de biblioteca C no namespace global.No entanto, seria permitido sobrecarregar
abs
se você fornecer diferentes tipos de parâmetros.fonte