__func__ 포인터의 두 constexpr 인스턴스의 차이점이 여전히 constexpr입니까?


14

이것이 유효한 C ++입니까?

int main() {
    constexpr auto sz = __func__ - __func__;
    return sz;
}

GCC와 MSVC는 괜찮다고 생각하지만 Clang은 그렇지 않다고 생각합니다. 컴파일러 탐색기 .


모든 컴파일러는 이것이 컴파일러 탐색기 라는 것에 동의합니다 .

int main() {
    constexpr auto p = __func__;
    constexpr auto p2 = p;
    constexpr auto sz = p2 - p;
    return sz;
}

Clang은 다시이 것을 좋아하지 않지만 다른 것은 괜찮습니다. 컴파일러 탐색기

int main() {
    constexpr auto p = __func__;
    constexpr auto p2 = __func__;
    constexpr auto sz = p2 - p;
    return sz;
}

여기 뭐야? 관련없는 포인터에 대한 산술은 정의되지 않은 동작이라고 생각하지만 __func__동일한 포인터를 반환합니다. 확실하지 않으므로 테스트 할 수 있다고 생각했습니다. 올바르게 기억하면 std::equal_to정의되지 않은 동작없이 관련없는 포인터를 비교할 수 있습니다.

#include <functional>

int main() {
    constexpr std::equal_to<const char*> eq{};
    static_assert(eq(__func__, __func__));
}

Clang 은 constexpreq(__func__, __func__) 이지만 상수 표현식이 아니라고 생각 합니다. 다른 컴파일러는 불평하지 않습니다 : 컴파일러 탐색기std::equal_to::operator()


Clang은 이것도 컴파일하지 않습니다. __func__ == __func__상수 표현식이 아니라고 불평합니다 . 컴파일러 탐색기

int main() {
    static_assert(__func__ == __func__);
}

에서 Function_definition , __func__같은-경우입니다 static const char __func__[] = "function-name";동등한 허용되고 그 데모를 ...
— Jarod42

흥미롭게도 constexpr 변수를 __func__사용하여 static_assert에서 constexpr 변수를 초기화 하고 사용 하면 작동합니다 .
— florestan

@ Jarod42 그래서 이것은 Clang의 버그입니까?
— Ayxan

@florestan 이런 식으로 ? Clang으로 컴파일되지 않습니다. 이 질문의 두 번째와 세 번째 예는 당신이 언급 한 방법입니다. 하나는 컴파일하고 다른 하나는 컴파일하지 않습니다.
— Ayxan

1
constexpr 평가에서 완전히 제거 할 수있는 CWG1962 도 참조하십시오 __func__.
— Davis Herring

답변:


13

__func__C ++에서 식별자입니다. 특히 특정 개체를 참조합니다. 가입일 [dcl.fct.def.general] / 8 :

함수 로컬 사전 정의 변수 _­_­func_­_­는 양식의 정의처럼 정의됩니다.

static const char __func__[] = "function-name";

여기서 function-name은 구현 정의 문자열입니다. 이러한 변수에 프로그램의 다른 오브젝트와 다른 주소가 있는지 여부는 지정되지 않았습니다.

A와 함수 소정 로컬 변수 ,이 정의 (있다면)를 함수 블록의 처음에 나타난다. 따라서 __func__해당 블록 내에서 사용 하면 해당 변수를 참조합니다.

"다른 객체"부분은 변수가 객체를 정의합니다. __func__해당 변수로 정의 된 객체의 이름을 지정합니다. 따라서 함수 내에서 모든 __func__이름 사용은 동일한 변수입니다. 정의되지 않은 것은 해당 변수 가 다른 객체와 다른 객체 인지 여부입니다 .

즉,라는 함수 에 있고 문제의 다른 곳에서 foo리터럴을 사용한 "foo"경우 구현 __func__에서 리터럴이 "foo"반환 하는 것과 동일한 객체를 구현하는 것이 금지되지 않습니다 . 즉, 표준은 __func__나타나는 모든 함수 가 문자열 리터럴 자체와 별도로 데이터를 저장해야 할 필요는 없습니다 .

이제 C ++의 "as as"규칙을 통해 구현에서이를 벗어날 수 있지만 감지 할 수있는 방식으로 는 구현할 수 없습니다 . 따라서 변수 자체는 다른 객체와 다른 주소를 가질 수도 있고 그렇지 않을 수도 있지만 __func__동일한 기능을 사용하는 경우 동일한 객체를 참조하는 것처럼 동작해야합니다.

Clang은 __func__이런 식 으로 구현하지 않는 것 같습니다 . 함수 이름의 prvalue 문자열 리터럴을 반환하는 것처럼 구현하는 것처럼 보입니다. 두 개의 고유 한 문자열 리터럴은 동일한 객체를 참조 할 필요가 없으므로 포인터를 빼는 것이 UB입니다. 그리고 상수 표현식 컨텍스트에서 정의되지 않은 동작은 잘못 구성됩니다.

Clang이 100 % 잘못되었다고 말하는 것을 주저하는 유일한 것은 [temp.arg.nontype] / 2 :

참조 또는 포인터 유형의 비 타입 템플릿 매개 변수의 경우 상수 표현식의 값은 참조하지 않아야합니다 (또는 포인터 유형의 경우 주소가 아니어야 함).

...

  • 사전 정의 된 _­_­func_­_변수

참조, 이것은 구현에 의해 약간의 혼란을 허용하는 것으로 보입니다. 즉, __func__기술적으로 상수식이 될 수 있지만 템플릿 매개 변수에는 사용할 수 없습니다. 기술적으로 변수이지만 문자열 리터럴처럼 취급됩니다.

어느 정도는 표준이 입의 양쪽에서 말하는 것입니다.


따라서 엄격히 말하면 __func__내 질문의 모든 경우에 일정한 표현이 될 수 있습니다. 따라서 코드는 컴파일되어야합니다.
— Ayxan

"이러한 변수에 프로그램의 다른 개체와 다른 주소가 있는지 여부는 지정되지 않았습니다." 부품? 지정되지 않은 동작은 추상 시스템의 동작에서 결정적이지 않음을 의미합니다. constexpr 평가에 문제가 될 수 있습니까? __func__주소 의 첫 번째 발생이 다른 개체의 발생과 동일하고 두 번째 발생 __func__이 아닌 경우 어떻게됩니까? 물론, 두 인스턴스간에 주소가 다르다는 것을 의미하지는 않지만 여전히 혼란스러워합니다!
— Johannes Schaub-litb

@ JohannesSchaub - litb : " 무엇에 대해"이 같은 변수가 프로그램의 다른 객체의 구별 주소가 있는지 여부를 "부분? 지정되지 않습니다. "어떻게 그것에 대해? __func__매크로가 아닙니다. 특정 변수와 특정 객체의 이름을 지정하는 식별자입니다. 따라서 __func__동일한 함수에서를 사용하면 동일한 객체를 나타내는 glvalue가 발생합니다. 또는 더 중요한 것은 이것이 사실이 아닌 방식으로 구현할 수 없다는 것입니다.
— Nicol Bolas

동일한 객체를 나타내는 @Nicol. 그러나 해당 개체는 한 순간에 다른 개체와 동일한 주소를 가질 수 있습니다. 그리고 다른 순간에는 그렇지 않았습니다. 나는 그것이 문제라고 말하지는 않지만, 모든 사람들에게이 가능성을 상기시켜줍니다. 그리고 결국, 나는 또한 착각 할 수도 있습니다. 그래서 나는 또한 정정되거나 확인되기를 희망하면서 이것을 말하고 있습니다.
— Johannes Schaub-litb

@ JohannesSchaub-litb : " 하지만 한 개체에서 다른 개체와 같은 주소를 가질 수 있습니다. "C ++ 개체 모델에서는 허용되지 않습니다. 두 개체 중 하나가 다른 개체에 중첩되어 있지 않으면 같은 저장소에서 동시에 같은 수명을 유지할 수 없습니다. 그리고 문제의 객체는 정적 저장 시간을 가지므로 배치를 사용하지 않으면 new프로그램이 끝날 때까지 아무데도 가지 않습니다.
— Nicol Bolas
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.