program tip

내 로그가 std 네임 스페이스에있는 이유는 무엇입니까?

radiobox 2020. 11. 12. 08:05
반응형

내 로그가 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

반응형