__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.