constexpr 함수가 상수 표현식인지 여부를 결정하는 것은 무엇입니까?
(사용 된 컴파일러는 내가 아는 한 c ++ 17의 gcc입니다 (Visual Studio에서 찾기가 어렵습니다))
#include <iostream>
using namespace std;
void increment( int& v )
{
++v;
}
int constexpr f()
{
int v = 0;
increment( v );
return v;
}
int main( )
{
cout << f( ) << '\n';
}
위 코드는 컴파일시 오류를 제공합니다.
constexpr 함수 'f'는 상수 표현식이 될 수 없습니다.
내가 이해하는 것처럼 이것은 함수 increment
가 constexpr 이 아니기 때문 입니다. 나를 혼란스럽게하는 것은 다음 코드가 잘 컴파일된다는 것입니다.
#include <iostream>
using namespace std;
void increment( int& v )
{
++v;
}
int constexpr f()
{
int v = 0;
for( int i = 0; i < 1; ++i )
{
increment( v );
}
return v;
}
int main( )
{
cout << f( ) << '\n';
}
이 코드는 기능적으로 동일하며 증가가 여전히 constexpr이 아니더라도 컴파일됩니다. [0, 1) 범위를 통한 for 루프가 컴파일러가 함수가 f
실제로 constexpr 임을 인식하게 만드는 방법을 이해하지 못합니다 .
누구든지 C ++의 constexpr과이 명백한 불일치에 대한 통찰력을 줄 수 있다면 크게 감사하겠습니다.
답변
두 프로그램 모두 [dcl.constexpr] / 6에 따라 "진단이 필요하지 않은 형식이 잘못되었습니다" .
기본값도 템플릿도 아닌 constexpr 함수 또는 constexpr 생성자의 경우 함수 또는 생성자의 호출이 핵심 상수 식의 평가 된 하위식이 될 수있는 인수 값이없는 경우, 생성자의 경우 다음의 평가 된 하위식이 될 수 있습니다. 일부 상수 초기화 객체 ( [basic.start.static] ) 의 초기화 전체 표현식 , 프로그램의 형식이 잘못되어 진단이 필요하지 않습니다.
gcc가 두 번째 프로그램의 문제를 알아 차리지 못했지만 여전히 준수하고 있다는 것이 조금 이상합니다.
f
예를 들어 실제로 상수 표현식이 필요한 컨텍스트에서 사용 된 경우 진단이 필요합니다 constexpr int n = f();
.
constexpr 함수에서는 허용되지 않는 것이 있습니다. 함수가 상수 표현식에서 사용되지 않더라도 진단 (일반적으로 오류 메시지)이 필요합니다 . cigien의 답변을 참조하십시오 . 그러나 문제의 프로그램은 이러한 엄격한 규칙을 위반하지 않습니다.
f
상수 식으로 호출하지 않기 때문에 정의 에 따라 상수 식으로 호출 할 수없는 컴파일러 를 진단하는 데 컴파일러가 필요한지 묻는 것 입니다.f
함수 정의 에 대한 요구 사항은 다음 과 같습니다 .constexpr
constexpr 함수의 정의는 다음 요구 사항을 충족해야합니다.
(3.1) 반환 유형 (있는 경우)은 리터럴 유형이어야합니다.
(3.2) 각각의 매개 변수 유형은 리터럴 유형이어야한다.
(3.3) 코 루틴이 될 수 없습니다.
(3.4) 함수가 생성자 또는 소멸자 인 경우 해당 클래스는 가상 기본 클래스를 갖지 않습니다.
(3.5) 기능 본체는
(3.5.1) goto 문,
(3.5.2) 식별자 라벨,
(3.5.3) 비 리터럴 유형 또는 정적 또는 스레드 저장 기간의 변수 정의.
알 수 있듯이의 정의 f
는 목록의 요구 사항을 위반하지 않습니다. 따라서 컴파일러는 이것을 진단하지 않기로 선택하면 준수합니다.
aschepler의 답변 에서 지적했듯이 , constexpr
이와 같은 함수 f
는 상수 표현식으로 호출 할 수 없지만 진단 할 수없는 것은 잘못된 형식의 진단이 필요하지 않은 것으로 간주됩니다.
f
컴파일 타임에 실제로 "호출"하지 않습니다 .
주 함수가 포함 된 경우 : static_assert(f() == 1, "f() returned 1");
"f () is not a constant expression"오류가 발생한다고 생각합니다.
다음은 관련 질문입니다.
표준에서는 constexpr
함수가 실제로는 일부 매개 변수 집합에 대해 컴파일 타임에 평가할 수 있어야 하지만 전부는 아닙니다. constexpr
어떤 상황에서는 컴파일 타임이 아닐 수있는 특정 작업을 수행 하는 함수 를 진단하기 위해 컴파일러가 필요하지 않습니다 . 이렇게하면 중지 문제를 해결하지 않아도됩니다.