2014-07-05 1 views
8

어쨌든 constexpr 인스턴스화 깊이를 구성 할 수 있습니까? -fconstexpr-depth = 4096 (clang/XCode 사용)으로 실행 중입니다.clang으로 constexpr 깊이 제한 (fconstexpr-depth가 작동하지 않는 것 같습니다)

그러나이 코드를 오류와 함께 컴파일하지 못했습니다. Constexpr 변수 fib_1은 상수 표현식으로 초기화해야합니다. -fconstexpr-depth = 4096 옵션의 설정 여부와 관계없이 코드가 실패합니다.

clang의 버그이거나 이와 같은 방식으로 작동 할 것으로 예상되는 버그입니까? 참고 :이 작업은 fib_cxpr (26), 27 실패 할 때까지 작동합니다.

코드 :

constexpr int fib_cxpr(int idx) { 
    return idx == 0 ? 0 : 
      idx == 1 ? 1 : 
      fib_cxpr(idx-1) + fib_cxpr(idx-2); 
} 

int main() { 
    constexpr auto fib_1 = fib_cxpr(27); 
    return 0; 
} 
+0

@ 브라이언 : 감사합니다. 어떻게 든 그것을 올바르게 포맷 할 수 없었습니다. – Sarang

+0

흠, GCC가 잘 처리합니다 ... –

+0

반면에 Clang은 전통적인 템플릿 스타일 메타 프로그램에 완벽하게 만족합니다. –

답변

16

TL; DR : 그 소리를 들어

는 명령 줄 인수 -fconstexpr-steps=1271242를 원하는 당신은 계산 이상의 -fconstexpr-depth=27


재귀 방법이 필요하지 않습니다 피보나치 수는 재귀 깊이가별로 필요하지 않습니다. fib(n)에 필요한 깊이는 실제로는 n입니다. 이것은 가장 긴 호출 체인이 fib(i-1) 재귀 호출을 통과하기 때문입니다.

constexpr auto fib_1 = fib_cxpr(3); // fails with -fconstexpr-depth=2, works with -fconstexpr-depth=3 
constexpr auto fib_1 = fib_cxpr(4); // fails with -fconstexpr-depth=3, works with -fconstexpr-depth=4 

따라서 -fconstexpr-depth은 중요한 설정이 아닙니다. 그 소리는 메시지 생성,

constexpr auto fib_1 = fib_cxpr(27); 

우리는 그 한계를 공격해야하는, -fconstexpr-depth=26로 컴파일 :

는 또한, 오류 메시지도 차이를 나타냅니다

note: constexpr evaluation exceeded maximum depth of 26 calls 

을하지만 -fconstexpr-depth=27 컴파일, 충분한 깊이 인 메시지는 다음과 같이 메시지를 생성합니다.

그래서 clang은 재귀 깊이와 '단계 제한'의 두 가지 실패를 구분한다는 것을 알고 있습니다.


'연타 최대 단계 제한'에 대한 상위 Google 결과

명령 줄 옵션의 구현을 포함하여이 기능을 구현하는 그 소리 패치에 대한 페이지로 이어질 : -fconstexpr-steps. 이 옵션을 검색하면 사용자 수준의 문서가 없음을 나타냅니다.

따라서 clang이 '단계'또는 얼마나 많은 '단계'clang이 fib(27)에 필요한지에 대한 문서는 없습니다. 우리는 이것을 정말로 높게 설정할 수는 있지만 나쁜 생각이라고 생각합니다. 대신, 일부 실험은 보여

n : steps 
0 : 2 
1 : 2 
2 : 6 
3 : 10 
4 : 18 

나타내는 것을 단계 (fib(n)) == 단계 (fib(n-1)) + 단계 (fib(n-2)) + 2 계산 약간 이에 따라 fib(27)는 연타 년대 1,271,242을 요구해야한다는 도시 단계. 따라서 -fconstexpr-steps=1271242으로 컴파일하면 프로그램을 컴파일 할 수 있어야합니다. 실제로는 it does입니다.-fconstexpr-steps=1271241으로 컴파일하면 이전과 동일한 오류가 발생하므로 정확한 제한이 있음을 알 수 있습니다.

덜 정확한 방법은 패치에서 기본 단계 제한이 1,048,576 (2) 인 것을 관찰하는 것입니다. 이는 분명히 fib(26)으로 충분합니다. 직관적으로 배가는 충분해야하며 초기 분석에서 2 백만 명이 충분하다는 것을 알 수 있습니다. 단단한 한도는 ⌈φ · steps() ⌉이다 (정확하게 1,271,242).


또 다른 주목할 점은 이러한 결과가 clang이 constexpr 평가의 메모를 수행하지 않는다는 것을 분명히 보여줍니다. GCC does,하지만 이것은 clang에서 전혀 구현되지 않은 것처럼 보입니다. 메모 작성으로 인해 메모리 요구 사항이 늘어나더라도이 경우와 같이 평가에 소요되는 시간을 크게 줄일 수 있습니다. 필자가이 글에서 결론을 내린 두 가지 결론은 좋은 컴파일 시간을 위해 memoization을 요구하는 constexpr 코드를 작성하는 것이 이식 가능한 코드에는 좋지 않으며 constexpr memoization과 명령 행 옵션을 지원하여 clang을 향상/비활성화 할 수 있다는 점이다.

+0

그래서 단계 자체가 피보나치 형식의 시퀀스입니까? –

+0

@BenVoigt 그래, 조금 우스운 것 같지만 이해가된다. (컴파일 된 예제에서 볼 수 있듯이 닫힌 양식을 작성하거나 똑같이 똑똑한 작업을 수행하는 대신 원본 함수의 복사본을 수정하여 단계 수를 계산했습니다.) – bames53

+0

@ bames53 : 감사합니다. 설명. 나는보고 된 의미 론적 문제의 확대를 놓쳤다 고 생각한다. XCode는 어떻게 잘못되었는지 잘 설명했습니다. – Sarang

관련 문제