언어 사양을 사용하면 전역 네임 스페이스 <cmath>
에서 표준 함수를 선언 (및 정의) 한 다음 using-declarations를 통해 네임 스페이스로 가져와 구현을 구현할 수 있습니다 . 이 접근법이 사용되는지 여부는 지정되지 않았습니다.std
20.5.1.2 헤더
4 [...] 그러나 C ++ 표준 라이브러리에서 선언 (C에서 매크로로 정의 된 이름 제외)은 네임 스페이스의 네임 스페이스 범위 (6.3.6) 내에 있습니다 std
. 이러한 이름 (21 ~ 33 절 및 부록 D에 추가 된 오버로드 포함)이 먼저 전역 네임 스페이스 범위 내에서 선언 된 다음 std
명시 적 using-declarations (10.3.3)에 의해 네임 스페이스 에 삽입되는지 여부는 지정되지 않습니다 .
분명히이 접근법을 따르기로 결정한 구현 중 하나 (예 : GCC)를 다루고 있습니다. 즉, 구현은을 제공 ::abs
하지만 std::abs
단순히를 "참조"합니다 ::abs
.
이 경우에 남아있는 한 가지 질문은 표준에 추가 ::abs
하여 자신의을 선언 할 수 있었던 ::abs
이유, 즉 다중 정의 오류가없는 이유입니다. 이는 일부 구현 (예 : GCC)에서 제공하는 다른 기능으로 인해 발생할 수 있습니다. 표준 기능을 소위 약한 기호 로 선언합니다. 하여 사용자가 자신의 정의로 "대체"할 수 있도록합니다.
이 두 가지 요소가 함께 관찰 된 효과를 생성합니다. 약한 기호 ::abs
를 대체하면 std::abs
. 이것이 언어 표준에 얼마나 잘 부합하는지는 다른 이야기입니다 ... 어쨌든이 행동에 의존하지 마십시오. 언어에 의해 보장되지 않습니다.
GCC에서이 동작은 다음과 같은 최소한의 예제로 재현 할 수 있습니다. 하나의 소스 파일
#include <iostream>
void foo() __attribute__((weak));
void foo() { std::cout << "Hello!" << std::endl; }
다른 소스 파일
#include <iostream>
void foo();
namespace N { using ::foo; }
void foo() { std::cout << "Goodbye!" << std::endl; }
int main()
{
foo();
N::foo();
}
이 경우 두 번째 소스 파일에서 ::foo
( "Goodbye!"
) 의 새 정의가 의 동작에도 영향을 미치는 것을 관찰 할 수 있습니다 N::foo
. 두 호출 모두 "Goodbye!"
. 그리고 ::foo
두 번째 소스 파일에서 의 정의를 제거하면 두 호출 모두의 "원래"정의 ::foo
및 출력으로 전달 "Hello!"
됩니다.
위의 20.5.1.2/4에서 부여한 권한은 <cmath>
. 구현은 단순히 C-style을 포함한 <math.h>
다음 함수를 다시 선언하고 std
일부 C ++ 관련 추가 및 조정을 추가 할 수 있습니다. 위의 설명이 문제의 내부 메커니즘을 적절하게 설명하는 경우 주요 부분은 C 스타일 버전 의 함수에 대한 약한 기호의 교체 가능성에 달려 있습니다.
우리는 단순히 세계적으로 대체 할 경우주의 int
로 double
는 출력 것이다 - 위의 프로그램에서, (GCC 아래) 코드는 "예상대로"작동합니다 -5 5
. 이것은 C 표준 라이브러리에 abs(double)
기능 이 없기 때문에 발생 합니다. 우리 자신을 선언함으로써 abs(double)
우리는 아무것도 대체하지 않습니다.
그러나로 전환 한 후 경우 int
에 double
우리는 또한 전환 abs
에 fabs
, 원래의 이상한 행동은 한창 (출력에 다시 나타납니다 -5 -5
).
이것은 위의 설명과 일치합니다.
abs
이 잘못되었습니다.