컴파일 시간 함수 실행
Compile-time function execution컴파일 시간 함수 실행(또는 컴파일 시간 함수 평가 또는 일반 상수 표현식)은 함수를 보통 머신 코드에 컴파일하고 런타임에 실행하는 컴파일러의 능력입니다.이는 함수에 대한 인수가 컴파일 시에 이미 알려져 있고 함수가 글로벌스테이트(순수한 함수)를 참조하거나 변경을 시도하지 않는 경우에 가능합니다.
일부 인수의 값만 알고 있다면 컴파일러는 여전히 일정 수준의 컴파일 시간 함수 실행(부분 평가)을 수행할 수 있으며, 인수가 알려지지 않은 경우보다 더 최적화된 코드를 생성할 수 있습니다.
예
리스프
Lisp 매크로 시스템은 동일한 언어로 사용자 정의 함수의 컴파일 시간 평가를 사용한 초기 사례입니다.
C++
C++로의 메타코드 확장(Vandevoorde 2003)[1]은 C++ 템플릿 메타프로그래밍의 개선된 구문으로서 컴파일 시간 함수 평가(CTFE)와 코드 주입을 가능하게 하는 초기 실험 시스템입니다.
이전 버전의 C++에서는 템플릿 메타프로그래밍이 컴파일 시 값을 계산하기 위해 자주 사용되었습니다.예를 들어 다음과 같습니다.
템플릿 < >인트 N> 구조 요인 { 열거하다 { 가치 = N * 요인< >N - 1>::가치 }; }; 템플릿 << 고객명 >>님 구조 요인< >0> { 열거하다 { 가치 = 1 }; }; // 요인 <4>::값 == 24 // 요인 설계<0>::값 == 1 무효 푸우() { 인트 x = 요인< >0>::가치; // == 1 인트 y = 요인< >4>::가치; // == 24 }
컴파일 시간 함수 평가를 사용하면 요인 계산에 사용되는 코드는 런타임 평가를 위해 작성되는 코드와 유사할 수 있다. 예를 들어 C++11 constexpr을 사용한다.
#실패하다 <cstdio> 콘스펙트 인트 요인(인트 n) { 돌아가다 n ? (n * 요인(n - 1)) : 1; } 콘스펙트 인트 f10 = 요인(10); 인트 주된() { 인쇄물(%d\n", f10); 돌아가다 0; }
C++11 에서는, 이 기술은 일반화 상수 표현이라고 불립니다(constexpr
C++14는 constexpr의 제약을 완화하여 로컬 선언과 조건 및 루프의 사용을 허용합니다(컴파일 시 실행에 필요한 모든 데이터를 사용할 수 있다는 일반적인 제한은 여전합니다).[2]
다음으로 C++14에서의 컴파일 시간 함수 평가 예를 나타냅니다.
// 컴파일 시 반복 요인. 콘스펙트 인트 요인(인트 n) { 인트 결과 = 1; 하는 동안에 (n > 1) { 결과 *= n--; } 돌아가다 결과; } 인트 주된() { 콘스펙트 인트 f4 = 요인(4); // f4 == 24 }
즉시 기능(C++)
C++20에서는 즉시 함수가 도입되어 컴파일 타임 함수의 실행이 보다 쉽고 유연하게 이루어졌습니다.constexpr
제약 사항
// 컴파일 시 반복 요인. 경시적 인트 요인(인트 n) { 인트 결과 = 1; 하는 동안에 (n > 1) { 결과 *= n--; } 돌아가다 결과; } 인트 주된() { 인트 f4 = 요인(4); // f4 == 24 }
이후 함수Factorial
마크가 붙어 있다consteval
는 컴파일 시에 확실하게 호출할 수 있습니다.또한 명백하게 일정한 다른 컨텍스트에서 강제로 호출되지 않습니다.따라서 즉시 함수의 사용은 메타프로그래밍 및 컴파일 시간 체크(C++20 텍스트 형식 라이브러리에서 사용)에서 광범위하게 사용됩니다.
다음은 컴파일 시간 함수 실행 시 즉시 함수를 사용하는 예입니다.
무효 이_오류_오류_왜냐하면_이_오류_가 표시되기 때문입니다.() {} 경시적 무효 캐서트(부울 b) { 한다면 (!b) 이_오류_오류_왜냐하면_이_오류_가 표시되기 때문입니다.(); } 경시적 무효 시험() { 인트 x = 10; 캐서트(x == 10); // OK(확인) x++; 캐서트(x == 11); // OK(확인) x--; 캐서트(x == 12); // 여기서 실패합니다. } 인트 주된() { 시험(); }
이 예에서는 즉시 함수가 상수 표현에서는 사용할 수 없는 함수를 호출했기 때문에 컴파일이 실패합니다.즉, 어설션이 실패하면 컴파일이 정지됩니다.
일반적인 컴파일 오류 메시지는 다음과 같습니다.
인 기능. '인트 주된()': 에 '콘스펙트' 팽창 의 '시험()' 에 '콘스펙트' 팽창 의 '캐서트(x == 12)' 에러: 불러 로. 하지 않다-'콘스펙트' 기능. '이_오류_오류_왜냐하면_이_오류_가 표시되기 때문입니다.()' 이_오류_오류_왜냐하면_이_오류_가 표시되기 때문입니다.(); ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~ [ ... ]
다음은 컴파일 시간 인수 체크를 활성화하는 컨스트럭터로 즉시 함수를 사용하는 다른 예입니다.
#실패하다 <string_view> #실패하다 <iostream> 무효 메시지_ends_with_his_error_point가 표시되므로() {} 구조 checked_메시지 { 표준::string_view 메시지; 경시적 checked_메시지(컨스턴트 차* arg) : 메시지(arg) { 한다면 (메시지.ends_와 함께('!')) 메시지_ends_with_his_error_point가 표시되므로(); } }; 무효 send_message_message(checked_메시지 arg) { 표준::외치다 << > arg.메시지 << > '\n'; } 인트 주된() { send_message_message("안녕, 세상아"); send_message_message("안녕, 세상아!"); }
여기서 컴파일이 실패하고 다음 메시지가 나타납니다.
인 기능. '인트 주된()': 에 '콘스펙트' 팽창 의 'checked_메시지(((컨스턴트 차*)"안녕, 세상아!"))' 에러: 불러 로. 하지 않다-'콘스펙트' 기능. '무효 메시지_ends_with_his_error_point가 표시되므로()' 메시지_ends_with_his_error_point가 표시되므로(); ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~ [ ... ]
D
다음은 D 프로그래밍 [3]언어의 컴파일 시간 함수 평가 예제입니다.
인트 요인(인트 n) { 한다면 (n == 0) 돌아가다 1; 돌아가다 n * 요인(n - 1); } // 컴파일 시 계산 열거하다 y = 요인(0); // == 1 열거하다 x = 요인(4); // == 24
이 예에서는 일반적으로 런타임에 평가되는 "요인"이라는 유효한 D 함수를 지정합니다.의 사용enum
는 변수 이니셜라이저를 컴파일 시 계산해야 함을 컴파일러에 알립니다.함수에 대한 인수는 [4]컴파일 시에도 해결할 수 있어야 합니다.
CTFE를 사용하면 컴파일 시 데이터 구조를 간단하게 채울 수 있습니다(D 버전 2).
인트[] genFactorials(인트 n) { 자동 결과 = 신규 인트[n]; 결과[0] = 1; 앞지르다 (i; 1 .. n) 결과[i] = 결과[i - 1] * i; 돌아가다 결과; } 열거하다 인자 = genFactorials(13); 무효 주된() {} // 컴파일 시 'factorials'에 다음 항목이 포함됩니다. // [1, 1, 2, 6, 24, 120, 720, 5_040, 40_320, 362_880, 3_628_800, // 39_916_800, 479_001_600]
CTFE를 사용하여 문자열을 생성할 수 있습니다.스트링은 D의 D코드로 해석 및 컴파일 됩니다.
레퍼런스
- ^ Daveed Vandevoorde, Edison Design Group (April 18, 2003). "Reflective Metaprogramming in C++" (PDF). Retrieved July 19, 2015.
- ^ Gabriel Dos Reis and Bjarne Stroustrup (March 2010). "General Constant Expressions for System Programming Languages. SAC-2010. The 25th ACM Symposium On Applied Computing" (PDF).
- ^ D 2.0 언어 사양:기능들
- ^ D 2.0 언어 사양:특성