int numeric-> 포인터 변환 규칙


19

다음 코드를 고려하십시오.

void f(double p) {}
void f(double* p) {}

int main()
{ f(1-1); return 0; }

MSVC 2017은이를 컴파일하지 않습니다. 1-1동일 0하고 따라서로 변환 될 수 있는 모호한 오버로드 된 호출 이 있음을 나타 double*냅니다. 다른 트릭 같은 0x0, 0L또는 static_cast<int>(0), 중 하나가 작동하지 않습니다. a const int Zero = 0를 호출하고 호출 하더라도 f(Zero)동일한 오류가 발생합니다. Zero이 아닌 경우에만 제대로 작동합니다 const.

동일한 문제가 GCC 5 이하에 적용되지만 GCC 6에는 적용되지 않는 것 같습니다. 이것이 C ++ 표준, 알려진 MSVC 버그 또는 컴파일러 설정의 일부인지 궁금합니다. 커서 Google은 결과를 얻지 못했습니다.

답변:


18

MSVC 1-1는 널 포인터 상수로 간주 합니다. 이것은 C ++ 03의 표준에 의해 정확했습니다. 값 0이 있는 모든 정수 상수 표현식 은 널 포인터 상수이지만 CWG 문제 가 90 C 인 C ++ 11의 경우 0 개의 정수 리터럴 만 null 포인터 상수가되도록 변경되었습니다 . 예제에서 볼 수 있듯이 표준에서 설명 했듯이 C ++ 14 표준 (draft. N4140)의 [diff.cpp03.conv] 를 참조하십시오 .

MSVC는이 변경 사항을 적합성 모드에서만 적용합니다. 따라서 코드로 /permissive-플래그 를 컴파일 하지만 MSVC 2019에서만 변경 사항이 구현 된 것 같습니다 . 여기를 참조 하십시오 .

GCC의 경우 GCC 5는 기본적으로 C ++ 98 모드이고, GCC 6 이상은 C ++ 14 모드로 설정되므로 동작 변경이 GCC 버전에 따라 달라지는 것 같습니다.

당신이 호출하면 f인수로 널 포인터 상수 널 포인터 상수가 어떤 포인터 타입의 널 포인터 값으로 변환 할 수 있기 때문에, 다음 호출은 모호하며이 변환의 변환과 동일한 순위를 가지고 int(또는 정수 계열 형식) 에 double.


-1

컴파일러는 [over.match][conv] 에 따라 ,보다 구체적으로 [conv.fpint] 및 [conv.ptr] 에 따라 올바르게 작동합니다 .

표준 변환 시퀀스는 [blah blah] 0 또는 1 개의 [...] 부동 적분 변환, 포인터 변환, [...]입니다.

정수 유형 또는 범위가 지정되지 않은 열거 유형의 prvalue는 부동 소수점 유형의 prvalue로 변환 될 수 있습니다. 가능한 경우 결과는 정확합니다 [blah blah]

널 포인터 상수는 값이 0이거나 [...] 인 정수 리터럴입니다. 널 포인터 상수는 포인터 유형으로 변환 될 수 있습니다. 결과는 해당 유형의 널 포인터 값입니다. [blah blah]

이제 과부하 해결 방법은 모든 후보 기능 중에서 가장 적합한 것을 선택하는 것입니다 (재미있는 기능으로서 통화 위치에서 액세스 할 필요조차 없습니다!). 가장 일치하는 항목은 정확한 매개 변수가 있거나 가장 적은 변환이있는 것입니다. 0 또는 1 개의 표준 변환이 발생할 수 있으며 (... 모든 매개 변수에 대해) 0은 1보다 "더 낫습니다".

(1-1)value가있는 정수 리터럴입니다 0.

정확히 하나의 변환으로 0 정수 리터럴을 각각double 또는 double*(또는 nullptr_t) 각각 으로 변환 할 수 있습니다 . 따라서 이러한 함수 중 둘 이상이 선언되었다고 가정하면 (예에서와 같이) 하나 이상의 후보가 존재하며 모든 후보가 동일하게 우수하고 일치하는 것이 없습니다. 모호하며 컴파일러가 불만을 제기하는 것이 옳습니다.


1
어떻게 정수 리터럴은 ? 값 과 연산자 가있는 두 개의 정수 리터럴을 포함하는 표현식 입니다. 1-11-
호두

@walnut : 아마도 "이진수, 8 진수, 숫자 또는 16 진수의 순서" 라는 어색한 표현을 참조 할 것입니다 . 그것은 "명백한"것을 뜻하는 불행한 말로, 그렇지 않은 것을 제안합니다 (즉, 빼기 문자 제외). "숫자"만 있고 "숫자"의 정의 (0 ... 9 중 하나)에 따라 음수 리터럴 (예 :) 을 가질 없습니다 -1. 그러나 기본 유형이 signed 이기 때문에 분명히 필요하며 명백히 가능하고 보편적으로 받아 들여집니다.
데이먼

1
표준 링크에 표시된 정수 리터럴에 대한 문법을 ​​참조하고 있는데 이는 일치하지 않습니다 1-1. C ++에는 음의 정수 리터럴이 없습니다. -1(A)의 최대 이루어진 표현 1(부호 형식의) 정수 리터럴 및 -단항 연산자. cppreference.com 의 "참고"섹션도 참조하십시오 .
호두

문법에 문법이없는 것은 사실이지만, 그 결과는 매우 중요하지 않습니다. 명시 적으로 추가하지 않으면 정의에 따라 리터럴이 서명 되므로 C ++에는 필연적으로 정의에 따라 음수 리터럴 많이 있습니다u . 부호있는 유형 에는 음수 값이 있습니다 (가능한 값의 약 50 %가 음수 임). 문법 (내가 알지 못하는 이유로)이 이런 식으로 오도 된 것은 불행히도, 기술적으로 (문법에 따르면) -1은 긍정적 인 문자이지만 다른 모든 방법으로 부정적입니다. 물론 부정적입니다. 오자. 3 + 4와 마찬가지로 문자 그대로입니다.
데이먼

그건 그렇고-나는 시도했다 0U. 같은 문제입니다. 내가 시도하지 않은 것은 enum가치입니다. 아마도 지명 된 사람이 변화했을 것입니다. 나는 함께 긴 표현을 쓰기 결국 decltyperemove_reference.
user1334767
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.