C ++ 함수 constexpr을 표시하는 것이 나쁜가요?


26

아주 사소한 기능이 주어지면

int transform(int val) {
    return (val + 7) / 8;
}

이 함수를 함수로 쉽게 변환하여 변수를 constexpr정의 할 때 constexpr다음과 같이 사용할 수 있다는 것이 매우 분명합니다 .

constexpr int transform(int val) {
    return (val + 7) / 8;
}

내 가정은 함수가 비 constexpr컨텍스트 에서 여전히 호출 될 수 있고 컴파일 타임 상수 변수를 정의하는 데 도움을 줄 수 있기 때문에 이것은 엄격하게 개선 된 것이라고 가정 합니다.

내 질문은, 이것이 나쁜 생각 인 상황이 있습니까? 마찬가지로이 기능을 만들어서 constexpr특정 상황에서이 기능을 더 이상 사용할 수 없거나 잘못 작동하는 상황을 경험할 수 있습니까?


1
내가 생각할 수있는 유일한 것은 컴파일러 버그였습니다. 재귀 적 constexpr 함수 호출로 인해 컴파일 단계가 느려지거나 컴파일러에서 메모리 충돌이 발생할 수 있습니다.
Zan Lynx

답변:


19

이것은 함수가 공용 인터페이스의 일부이고 향후 버전의 API를 이진 호환으로 유지하려는 경우에만 중요합니다. 이 경우 API의 발전 방법과 향후 변경을 위해 확장 점이 필요한 위치를 신중하게 고려해야합니다.

그것은 constexpr한정자를 결정적인 디자인 결정으로 만듭니다. 호환되지 않는 API 변경없이이 규정자를 제거 할 수 없습니다. 또한 해당 기능을 구현할 수있는 방법을 제한합니다 (예 :이 기능 내에서 로깅을 수행 할 수 없음). 모든 사소한 기능이 영원히 사소한 상태를 유지하는 것은 아닙니다.

즉, 당신이 바람직 사용해야 constexpr있습니다 기능에 본질적으로 순수 함수, 즉 컴파일시에 실제로 도움이 될 것입니다 (예를 들어 템플릿 메타 프로그래밍에 대한). 현재 구현이 constexprable 가능하기 때문에 함수를 constexpr로 만드는 것은 좋지 않습니다.

컴파일 타임 평가가 필요하지 않은 경우, 인라인 함수 또는 내부 링크가있는 함수를 사용하는 것이 더 적합 할 것입니다 constexpr. 이러한 모든 변형은 기능 본문이 "공개"이며 호출 위치와 동일한 컴파일 단위로 사용 가능하다는 공통점이 있습니다.

문제의 함수가 안정적인 공개 API의 일부가 아닌 경우 임의로 디자인을 임의로 변경할 수 있으므로 문제가되지 않습니다. 그러나 이제 모든 호출 사이트를 제어하므로 constexpr 함수를 "경우에 따라"표시 할 필요는 없습니다. 당신은 알고 당신이 constexpr 컨텍스트에서이 기능을 사용하는지 여부. 불필요하게 제한적인 한정자를 추가하면 난독 처리로 간주 될 수 있습니다.


12

함수를 표시 constexpr하면 인라인 함수가됩니다. [dcl.constexpr] / 1 :

constexpr 지정자로 선언 된 함수 또는 정적 데이터 멤버는 암시 적으로 인라인 함수 또는 변수 (7.1.6)입니다.

inline따라서 해당 함수의 정의를 사용할 수있는 모든 번역 단위에 포함시켜야 함을 의미합니다. 기본적으로 constexpr함수는 다음 중 하나 여야합니다.

  1. 하나의 번역 단위로 사용이 제한되거나
  2. 헤더에 정의되어 있습니다.

헤더에서 선언하고 소스 파일에서 정의하려는 대부분의 일반적인 함수는 헤더를 포함하고 소스의 객체 파일에 대한 링크 만 포함하면 constexpr작동하지 않습니다.

이론적으로는 모든 것을 헤더로 옮기고 모든 헤더를 포함하는 하나의 소스 파일 만 가질 수 있다고 가정하지만 컴파일 시간이 크게 줄어들고 대부분의 심각한 프로젝트의 경우 컴파일하는 데 엄청난 양의 메모리가 필요합니다.

constexpr기능은 어떤 방법으로 제한되기 때문에 일부 기능은 전혀 옵션이 될 수 없습니다. 제한 사항은 다음과 같습니다.

  1. 가상 함수가 없는constexpr.
  2. 반환 유형은 '리터럴 유형'이어야합니다 (예를 들어, 트라이 벌이 아닌 ctor 또는 dtor를 가진 개체가 없음).
  3. 모든 매개 변수는 리터럴 유형이어야합니다.
  4. 함수 본문은 try블록을 포함 할 수 없습니다 .
  5. 리터럴이 아닌 유형의 변수 정의 나 정적 또는 스레드 저장 기간이있는 항목은 포함 할 수 없습니다.

나는 다소 모호한 것들을 건너 뛰었지만 (예를 들어, goto또는 asm진술을 포함 할 수도 없음 ) 아이디어를 얻습니다.

결론 : 예, 이것이 좋지 않은 아이디어가있는 상황이 꽤 있습니다.


"C ++ 20까지 가상이 아니어야합니다"가상 함수가 어떻게 constexpr 일 수 있는지 궁금합니다. 컴파일러는 무엇을합니까?
chaosink
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.