[c++] C ++ 20 이전에 std :: swap 표시된 constexpr이 아닌 이유는 무엇입니까?
C ++ 20, std::swap
a가됩니다 constexpr
기능.
나는 표준 라이브러리가 사물을 표시하는 데 실제로 언어보다 뒤떨어져 있음을 알고 constexpr
있지만 2017 년 <algorithm>
에는 다른 것들과 마찬가지로 거의 constexpr이었습니다. 그러나 std::swap
그렇지 않았습니다. 나는 그 표시를 막는 이상한 언어 결함이 있다는 것을 모호하게 기억하지만 세부 사항은 잊어 버립니다.
누군가 간결하고 명확하게 설명 할 수 있습니까?
동기 부여 : C ++ 11 / C ++ 14 코드에서 std::swap()
유사한 함수 를 표시하는 것이 왜 나쁜 아이디어인지 이해해야 constexpr
합니다.
답변
이상한 언어 문제는 CWG 1581입니다 .
15 절 [특별]은 특수 멤버 함수가 사용시에만 암시 적으로 정의된다는 것을 완벽하게 명확하게 알 수 있습니다. 이것은 평가되지 않은 컨텍스트에서 상수 표현식에 대한 문제를 만듭니다.
struct duration { constexpr duration() {} constexpr operator int() const { return 0; } }; // duration d = duration(); // #1 int n = sizeof(short{duration(duration())});
여기서 문제는 우리
constexpr duration::duration(duration&&)
가이 프로그램에서 암시 적으로 정의 할 수 없으므로 초기화 목록의 표현식이 상수 표현식이 아닙니다 (정의되지 않은 constexpr 함수를 호출하기 때문에) 따라서 프로그램이 잘못 구성되었습니다.1 행의 주석을 해제하면 이동 생성자가 암시 적으로 정의되고 프로그램이 유효합니다. 멀리서이 무시 무시한 행동은 매우 불행합니다. 이 시점에서 구현이 다양합니다.
나머지 문제 설명을 읽을 수 있습니다.
이 문제에 대한 해결책 은 2017 년 앨버 커키 P0859 (C ++ 17 출하 후)에 채택되었습니다 . 이 문제는 C ++ 20 모두에 대해 ( P0879constexpr std::swap
에서 해결됨 ) 및 constexpr std::invoke
( PWG65 에서 CWG1581 예제가 있는 P1065 에서 해결됨 ) 둘 다 가질 수있는 차단제였습니다 .
내 생각에 가장 이해하기 쉬운 예는 P1065에서 지적한 LLVM 버그 보고서의 코드입니다.
template<typename T> int f(T x) { return x.get(); } template<typename T> constexpr int g(T x) { return x.get(); } int main() { // O.K. The body of `f' is not required. decltype(f(0)) a; // Seems to instantiate the body of `g' // and results in an error. decltype(g(0)) b; return 0; }
CWG1581은 constexpr 멤버 함수가 정의 된 시점 에 관한 것이며 해상도는 사용시에만 정의되도록합니다. P0859 이후에는 위의 형식이 양호합니다 (유형은 b
입니다 int
).
이후 std::swap
와 std::invoke
모두하는 멤버 함수에 대한 (이전의 이동 건축 / 할당하고 호출 연산자 / 후자의 대리 전화), 그들은 모두이 문제의 해결에 의존 확인에 의존해야합니다.
답변
이유
(@NathanOliver로 인해)
constexpr
스왑 기능 을 허용하려면 이 기능에 대한 템플릿을 인스턴스화하기 전에 스왑 된 유형이 이동 구성 가능하고 이동 지정 가능한지 확인해야합니다. 불행하게도, 결함에만 C ++ 20에서 해결 언어로 인해, 당신은 할 수없는 관련 멤버 함수가 멀리 컴파일러에 관한 한, 아직 정의되지 않았을 수 있기 때문에, 그 확인합니다.
연대기
- 2016 : 안토니 Polukhin submitts 제안 P0202 의 모든 표시하는
<algorithm>
등의 기능을constexpr
. - 표준위원회의 핵심 실무 그룹은 결함 CWG-1581에 대해 논의 합니다. 이 문제는 문제가 만들어
constexpr std::swap()
도constexpr std::invoke()
위의 설명을 참조 -. - 2017 : 안토니는 개정 그의 몇 번 제외 할 제안
std::swap
과 다른 구조를, 이것은 C ++ (17)에 허용됩니다. - 2017 : CWG-1581 문제에 대한 해결책은 P0859 로 제출 되어 2017 년 표준위원회 (C ++ 17 출하 후)에서 승인되었습니다.
- 2017 년 말 : Antony는 CWG-1581 결의 후 constexpr 을 만들기 위해 보완 제안 P0879를 제출합니다
std::swap()
. - 2018 : 보완 제안이 C ++ 20에 허용됩니다 (?). 배리가 지적했듯이 constexpr
std::invoke()
수정도 마찬가지입니다 .
특정 사례
당신이 사용할 수있는 constexpr
당신이 경우에 교환을 하지 않는 이동-constructibility 및 이동 – 양도성 확인, 오히려 특정의 것을 보장 유형의 다른 기능을 확인합니다. 예를 들어 기본 유형 만 있고 클래스 나 구조체는 없습니다. 또는 이론적으로 검사를 포기하고 발생할 수있는 컴파일 오류와 컴파일러 간 비정상적인 동작 전환을 처리 할 수 있습니다. 어쨌든 std::swap()
그런 종류의 물건으로 바꾸지 마십시오 .