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

이것이 유효한 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__);
}



답변

__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__기술적으로 상수식이 될 수 있지만 템플릿 매개 변수에는 사용할 수 없습니다. 기술적으로 변수이지만 문자열 리터럴처럼 취급됩니다.

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


답변