programing tip

선언이 std 네임 스페이스에 영향을 미칠 수 있습니까?

itbloger 2020. 8. 29. 09:34
반응형

선언이 std 네임 스페이스에 영향을 미칠 수 있습니까?


#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;
}

출력이 -5and 가 될 것으로 예상 5했지만 출력은 -5and -5입니다.

이 사건이 왜 일어날 지 궁금합니다.

사용과 관련이 std있습니까?


언어 사양을 사용하면 전역 네임 스페이스 <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();
}

In this case you will also observe that the new definition of ::foo ("Goodbye!") in the second source file also affects the behavior of N::foo. Both calls will output "Goodbye!". And if you remove the definition of ::foo from the second source file, both calls will dispatch to the "original" definition of ::foo and output "Hello!".


The permission given by the above 20.5.1.2/4 is there to simplify implementation of <cmath>. Implementations are allowed to simply include C-style <math.h>, then redeclare the functions in std and add some C++-specific additions and tweaks. If the above explanation properly describes the inner mechanics of the issue, then a major part of it depends on replaceability of weak symbols for C-style versions of the functions.

Note that if we simply globally replace int with double in the above program, the code (under GCC) will behave "as expected" - it will output -5 5. This happens because C standard library does not have abs(double) function. By declaring our own abs(double), we do not replace anything.

But if after switching from int with double we also switch from abs to fabs, the original weird behavior will reappear in its full glory (output -5 -5).

This is consistent with the above explanation.


Your code causes undefined behaviour.

C++17 [extern.names]/4:

Each function signature from the C standard library declared with external linkage is reserved to the implementation for use as a function signature with both extern "C" and extern "C++" linkage, or as a name of namespace scope in the global namespace.

So you cannot make a function with the same prototype as the Standard C library function int abs(int);. Regardless of which headers you actually include or whether those headers also put C library names into the global namespace.

However, it would be allowed to overload abs if you provide different parameter types.

참고URL : https://stackoverflow.com/questions/50898508/can-a-declaration-affect-the-std-namespace

반응형