내 로그가 std 네임 스페이스에있는 이유는 무엇입니까?
아래 코드에서 나는 사소한 log
기능을 정의 합니다. 에서 main
내가하려고 하지 를 호출; 전화 std::log
합니다. 그럼에도 불구하고 내 자신 log
이 불린다. 그리고 "로그!" 화면에. 이유를 아는 사람이 있습니까? 저는 G ++ 4.7과 clang ++ 3.2를 사용합니다.
#include <iostream>
#include <cmath>
double log(const double x) { std::cout << "log!\n"; return x; }
int main(int argc, char *argv[])
{
std::log(3.14);
return 0;
}
C ++ 표준 17.6.1.2 단락 4 (강조 내) :
18 ~ 30 절 및 부록 D에 명시된 경우를 제외하고 각 헤더의 내용은 C 표준 라이브러리 (1.2) 또는 C Unicode TR에 지정된대로
cname
해당 헤더 의 내용과 동일해야합니다.name.h
포함. 그러나 C ++ 표준 라이브러리에서 선언 (C에서 매크로로 정의 된 이름 제외)은 namespace의 네임 스페이스 범위 (3.3.6) 내에 있습니다std
. 이러한 이름이 전역 네임 스페이스 범위 내에서 처음 선언 된 다음std
명시 적 using-declarations (7.3.3)에 의해 네임 스페이스 에 삽입되는지 여부는 지정되지 않습니다 .
g ++는 동일한 헤더 파일 중 일부를 C 및 C ++에 재사용 할 수 있도록 후자의 방식으로 수행합니다. 따라서 g ++는 double log(double)
전역 네임 스페이스에서 선언하고 정의 할 수 있습니다.
섹션 17.6.4.3.3 단락 3 및 4 :
외부 연결로 선언 된 표준 C 라이브러리의 각 이름은
extern "C"
네임 스페이스std
와 전역 네임 스페이스 모두에서 연결이 있는 이름으로 사용하기 위해 구현에 예약되어 있습니다.외부 연결로 선언 된 표준 C 라이브러리의 각 함수 서명은
extern "C"
및extern "C++"
연결 이 모두있는 함수 서명으로 사용 하거나 전역 네임 스페이스의 네임 스페이스 범위 이름으로 사용하기 위해 구현에 예약되어 있습니다.
섹션 17.6.4.3, 단락 2의 맨 위에 있습니다.
프로그램이이 절에서 명시 적으로 허용하는 것 외에 예약 된 컨텍스트에서 이름을 선언하거나 정의하는 경우 해당 동작은 정의되지 않습니다.
반면에 귀하 는 어떤 방식 으로든 선언하거나 정의 할 수 없습니다::log
.
그래도 g ++ 툴체인이 오류 메시지를 표시하지 않는 것은 너무 나쁩니다.
내가 기대하는 일은 std::log
단순히 ::log
. 불행히도 과부하 ::log
만 제공하고 float
친절하게 double
과부하를 제공 하여 더 나은 일치를 만듭니다. 그러나 나는 그것이 과부하 세트에서 어떻게 고려되는지 여전히 알지 못합니다.
libstdc ++의 경우 cmath
다음과 같이 표시됩니다.
using ::log;
따라서 전역 네임 스페이스의 math.h 함수를 std
. 불행히도에 대한 구현을 제공하고 double log(double)
있으므로 링커는 수학 lib 의 구현을 사용하지 않습니다.
그래서 확실히 libstdc ++의 버그입니다
.
편집 : std::log
명시 적으로 std::
버전을 요청할 때 C 라이브러리와의 간섭을 겪지 않아야 하기 때문에 libstdc ++의 버그라고 주장합니다 . 물론 표준 라이브러리 함수를 재정의하는이 방법은 C 언어의 오래된 "기능"입니다.
편집 2 : 표준이 실제로 전역 네임 스페이스에서 .NET으로 이름을 가져 오는 것을 금지하지 않는다는 것을 알았습니다 std
. 따라서 결국 버그가 아니라 구현 세부 사항의 결과 일뿐입니다.
C ++에서 컴파일러는 전역 네임 스페이스에 C 라이브러리를 자유롭게 구현하고 위임 할 수 있습니다 (구현 정의 됨).
17.6.1.2.4 조항 18 ~ 30 및 부록 D에 명시된 경우를 제외하고 각 헤더 cname의 내용은 C 표준 라이브러리 (1.2) 또는 C에 지정된대로 해당 헤더 이름 .h의 내용과 동일해야합니다. 유니 코드 TR (해당되는 경우 포함). 그러나 C ++ 표준 라이브러리에서 선언 (C에서 매크로로 정의 된 이름 제외)은 네임 스페이스 std의 네임 스페이스 범위 (3.3.6) 내에 있습니다. 이러한 이름이 전역 네임 스페이스 범위 내에서 처음 선언 된 다음 명시적인 using-declarations (7.3.3)에 의해 네임 스페이스 std에 삽입되는지 여부는 지정되지 않습니다.
일반적으로 C 표준 라이브러리 중 하나와 동일한 서명으로 함수를 만드는 것을 피할 것입니다. C ++ 표준은 컴파일러가 선택하는 경우 이러한 서명을 자유롭게 사용할 수 있도록합니다. 즉, 동일한 서명을 사용하려고하면 컴파일러와 싸울 수 있습니다. 따라서 이상한 결과를 얻습니다.
링커 오류 또는 경고가 예상되며이를보고 할 가치가 있다고 생각합니다.
[편집하다]
와우, 닌자.
전역 네임 스페이스에서 재정의했기 때문입니다. 예를 들어 Nim 과 같은 더 안전하고 깨끗한 언어로 이동하고 싶지 않은 경우 네임 스페이스를 사용하면 이러한 위험을 피할 수 있습니다 .
#include <iostream>
#include <cmath> // Uses ::log, which would be the log() here if it were not in a namespace, see http://stackoverflow.com/questions/11892976/why-is-my-log-in-the-std-namespace
// Silently overrides std::log
//double log(double d) { return 420; }
namespace uniquename {
using namespace std; // So we don't have to waste space on std:: when not needed.
double log(double d) {
return 42;
}
int main() {
cout << "Our log: " << log(4.2) << endl;
cout << "Standard log: " << std::log(4.2);
return 0;
}
}
// Global wrapper for our contained code.
int main() {
return uniquename::main();
}
산출:
Our log: 42
Standard log: 1.43508
참고 URL : https://stackoverflow.com/questions/11892976/why-is-my-log-in-the-std-namespace
'program tip' 카테고리의 다른 글
컴파일러가 아닌 C ++ 인터프리터를 사용 했습니까? (0) | 2020.11.12 |
---|---|
USB로 연결된 Android 모바일 장치에서 PC의 로컬 호스트에 액세스 (0) | 2020.11.12 |
이 std :: ref 동작이 논리적입니까? (0) | 2020.11.12 |
iPhone 애플리케이션을 AppStore에 업로드하는 단계 (0) | 2020.11.12 |
로그인 요청 인증 토큰 문제 (0) | 2020.11.12 |