컴파일 타임 함수 실행
"오늘의AI위키"의 AI를 통해 더욱 풍부하고 폭넓은 지식 경험을 누리세요.
1. 개요
컴파일 타임 함수 실행(CTFE)은 컴파일 시간에 함수를 실행하는 프로그래밍 기법이다. 리스프 매크로 시스템이 초기 사례이며, C++에서는 템플릿 메타프로그래밍을 통해 구현되었다. C++11에서 `constexpr` 키워드가 도입되어 일반화되었고, C++14에서 제약이 완화되었다. C++20에서는 `consteval` 키워드를 사용하는 즉시 함수가 도입되어 컴파일 타임에만 실행되는 함수를 명시적으로 정의할 수 있게 되었다. D 언어는 `enum`을 사용하여 CTFE를 지원하며, Zig는 `comptime` 키워드를 통해 지원한다. CTFE는 메타 프로그래밍, 컴파일 타임 검사, 제네릭 데이터 구조 생성 등에 활용된다.
더 읽어볼만한 페이지
- 컴파일러 최적화 - 데이터 흐름 분석
데이터 흐름 분석은 프로그램의 제어 흐름 그래프를 바탕으로 변수의 정의, 사용, 생존 여부를 분석하며, 전이 함수와 결합 연산을 통해 데이터 흐름 정보를 계산하고 반복적으로 갱신하여 해를 구한다. - 컴파일러 최적화 - 느긋한 계산법
느긋한 계산법은 계산 결과가 필요할 때까지 계산을 늦추는 방식으로, 함수형 프로그래밍 언어에서 유용하게 사용되며 무한 데이터 구조를 다루거나 불필요한 계산을 피하는 데 효과적이다. - 컴파일러 구성 - 구문 분석
구문 분석은 입력 데이터를 구조화된 형태로 변환하는 과정으로, 컴퓨터 언어에서는 소스 코드를 분석하여 추상 구문 트리를 생성하고, 자연어 처리에서는 텍스트의 문장 구조와 의미를 분석한다. - 컴파일러 구성 - 바이너리 재컴파일러
컴파일 타임 함수 실행 |
---|
2. 역사
컴파일 타임 함수 실행의 초기 개념은 리스프의 매크로 시스템에서 찾을 수 있다. 리스프 매크로는 사용자 정의 함수를 컴파일 타임에 평가하여 코드를 생성하는 기능을 제공했다.
C++의 메타코드 확장(Vandevoorde 2003)은 컴파일 타임 함수 평가(CTFE)와 C++ 템플릿 메타프로그래밍을 위한 개선된 문법으로서 코드 인젝션을 허용하는 실험적인 초기 시스템이었다.[7] C++11에서는 이 기법이 일반화된 상수 표현(constexpr
)으로 알려졌으며,[8] C++14에서는 constexpr에 대한 제한이 완화되었다.
2. 1. C++
초기 버전의 C++에서는 템플릿 메타프로그래밍을 통해 컴파일 타임에 값을 계산하는 기법이 사용되었다.[7][1] 예를 들어, 다음과 같이 팩토리얼 값을 컴파일 타임에 계산할 수 있었다.template
enum {
value = N * Factorial
};
};
template <> struct Factorial<0> {
enum { value = 1 };
};
// Factorial<4>::value == 24
// Factorial<0>::value == 1
void foo() {
int x = Factorial<0>::value; // == 1
int y = Factorial<4>::value; // == 24
}
C++11에서는 `constexpr` 키워드를 도입하여 일반화된 상수 표현식(일반화된 상수 표현식)을 지원하면서 컴파일 타임 함수 실행(CTFE)의 개념이 발전했다.[8][2] `constexpr`를 사용하면 런타임 평가를 위해 작성하는 코드와 유사한 방식으로 컴파일 타임에 팩토리얼을 계산할 수 있다.
#include
constexpr int factorial(int n) {
return n ? (n * factorial(n - 1)) : 1;
}
constexpr int f10 = factorial(10);
int main() {
printf("%d\n", f10);
return 0;
}
C++14에서는 `constexpr`의 제약 조건을 완화하여 지역 변수 선언, 조건문, 반복문 등을 사용할 수 있게 되면서 컴파일 타임 함수 실행이 더욱 유연해졌다. 다음은 C++14에서 컴파일 타임 함수 실행의 예시이다.
// 컴파일 타임에 반복적인 팩토리얼.
constexpr int Factorial(int n) {
int result = 1;
while (n > 1) {
result *= n--;
}
return result;
}
int main() {
constexpr int f4 = Factorial(4); // f4 == 24
}
C++20에서는 `consteval` 키워드를 사용하는 즉시 함수(immediate function)를 도입하여 컴파일 타임에만 실행되는 함수를 명시적으로 정의할 수 있게 되었다. 즉시 함수는 메타 프로그래밍 및 컴파일 타임 검사에 유용하게 활용된다.
// 컴파일 타임에 반복적인 팩토리얼 계산
consteval int Factorial(int n) {
int result = 1;
while (n > 1) {
result *= n--;
}
return result;
}
int main() {
int f4 = Factorial(4); // f4 == 24
}
2. 2. 기타 언어
D 언어는 `enum`을 사용하여 컴파일 타임에 값을 계산하고, CTFE를 통해 데이터 구조를 초기화하거나 문자열을 생성하는 기능을 제공한다.[3][4] 다음은 D 언어에서 컴파일 타임 함수 실행 예시이다.```D
int factorial(int n) {
if (n == 0)
return 1;
return n * factorial(n - 1);
}
// 컴파일 타임에 계산됨
enum y = factorial(0); // == 1
enum x = factorial(4); // == 24
```
위 예시는 일반적으로 런타임에 평가되는 "factorial"이라는 유효한 D 함수를 지정한다. `enum`을 사용하면 변수의 초기화 값이 컴파일 시간에 계산되어야 함을 컴파일러에 알린다.
CTFE는 간단한 방식으로 컴파일 시간에 데이터 구조를 채우는 데 사용할 수 있다(D 버전 2).
```D
int[] genFactorials(int n) {
auto result = new int[n];
result[0] = 1;
foreach (i; 1 .. n)
result[i] = result[i - 1] * i;
return result;
}
enum factorials = genFactorials(13);
void main() {}
// '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 코드로 구문 분석되고 컴파일된다.
Zig 프로그래밍 언어는 `comptime` 키워드를 사용하여 컴파일 타임 함수 실행을 지원하며, 컴파일 타임 매개변수를 통해 제네릭 데이터 구조를 생성하는 데 활용할 수 있다.[5][6] 다음은 Zig에서 컴파일 타임 함수 실행의 예시이다.
```Zig
pub fn factorial(n: usize) usize {
var result = 1;
for (1..(n + 1)) |i| {
result *= i;
}
return result;
}
pub fn main() void {
const x = comptime factorial(0); // == 0
const y = comptime factorial(4); // == 24
}
```
위 예시는 일반적으로 런타임에 평가될 "factorial"이라는 유효한 Zig 함수를 지정한다. `comptime`을 사용하면 변수의 초기화가 컴파일 시간에 계산되어야 함을 컴파일러에 알린다.
Zig는 또한 컴파일 타임 매개변수를 지원한다.
```Zig
pub fn factorial(comptime n: usize) usize {
var result: usize = 1;
for (1..(n + 1)) |i| {
result *= i;
}
return result;
}
pub fn main() void {
const x = factorial(0); // == 0
const y = factorial(4); // == 24
}
```
CTFE는 컴파일 시간에 제네릭 데이터 구조를 만드는 데 사용할 수 있다.
```Zig
fn List(comptime T: type) type {
return struct {
items: []T,
len: usize,
};
}
// The generic List data structure can be instantiated by passing in a type:
var buffer: [10]i32 = undefined;
var list = List(i32){
.items = &buffer,
.len = 0,
};
3. C++에서의 활용
C++에서는 컴파일 타임 함수 실행을 통해 다양한 기능을 구현할 수 있다.
초기 버전의 C++에서는 템플릿 메타프로그래밍이 컴파일 타임에 값을 계산하기 위해 자주 사용되었다.[7] C++11에서는 이 기법이 일반화된 상수 표현식(`constexpr`)으로 알려졌으며, `constexpr` 함수를 사용하면 런타임과 컴파일 타임 모두에서 실행 가능한 함수를 작성할 수 있다.[8]
C++14에서는 `constexpr`에 대한 제한이 완화되어 로컬 변수 정의, 조건문, 순환문의 사용이 허용되었다.[2] C++20에서는 즉시 함수(immediate function)가 도입되어 컴파일 타임 함수 실행이 더 접근성이 좋고 유연해졌으며, 메타 프로그래밍 및 컴파일 타임 검사에 광범위하게 사용될 수 있다.
3. 1. 템플릿 메타프로그래밍
초기 버전의 C++에서, 템플릿 메타프로그래밍은 컴파일 타임에 값을 계산하기 위해 자주 사용되었다. 다음은 그 예시이다.[7]```cpp
template
struct Factorial {
enum { value = N * Factorial
};
template <>
struct Factorial<0> {
enum { value = 1 };
};
// Factorial<4>::value == 24
// Factorial<0>::value == 1
void foo() {
int x = Factorial<0>::value; // == 1
int y = Factorial<4>::value; // == 24
}
```
컴파일 타임 함수 실행을 사용하면, 팩토리얼(계승)을 계산하는 데 사용되는 코드는 C++11 `constexpr`을 사용하는 런타임 평가를 위해 쓰는 것과 비슷할 것이다.[8]
3. 2. constexpr
C++11에서, 이 기법은 일반화된 상수 표현식(`constexpr`)으로 알려졌다.[8] `constexpr` 함수를 사용하면 런타임과 컴파일 타임 모두에서 실행 가능한 함수를 작성할 수 있다. C++11 `constexpr`을 사용하는 런타임 평가를 위해 쓰는 코드는 컴파일 타임 함수 평가를 사용하는 코드와 비슷하다.#include
constexpr int factorial(int n) {
return n ? (n * factorial(n - 1)) : 1;
}
constexpr int f10 = factorial(10);
int main() {
printf("%d\n", f10);
return 0;
}
C++14는 `constexpr`에 대한 제한을 풀어주어, 로컬 변수 정의, 조건문, 순환문의 사용을 허용하였다 (모든 데이터가 실행을 위해 요구되는 일반적인 제한은 컴파일 타임에도 유효하다).[2]
다음은 C++14에서 컴파일 타임 함수 실행의 예시이다.
// 컴파일 타임에 반복적인 팩토리얼.
constexpr int Factorial(int n) {
int result = 1;
while (n > 1) {
result *= n--;
}
return result;
}
int main() {
constexpr int f4 = Factorial(4); // f4 == 24
}
3. 3. consteval (즉시 함수)
C++20에서 즉시 함수(immediate function)가 도입되었고, 완화된 `constexpr` 제한으로 컴파일 타임 함수 실행이 더 접근성이 좋고 유연해졌다.```cpp
// 컴파일 타임에 반복적인 팩토리얼 계산
consteval int Factorial(int n) {
int result = 1;
while (n > 1) {
result *= n--;
}
return result;
}
int main() {
int f4 = Factorial(4); // f4 == 24
}
```
`Factorial` 함수는 `consteval`로 표시되어 있으므로 컴파일 타임에 호출이 보장된다. 따라서 즉시 함수는 메타 프로그래밍 및 컴파일 타임 검사(C++20 텍스트 서식 라이브러리에서 사용)에 광범위하게 사용될 수 있다.
다음은 컴파일 타임 함수 실행에서 즉시 함수를 사용하는 예이다.
```cpp
void you_see_this_error_because_assertion_fails() {}
consteval void cassert(bool b) {
if (!b)
you_see_this_error_because_assertion_fails();
}
consteval void test() {
int x = 10;
cassert(x == 10); // ok
x++;
cassert(x == 11); // ok
x--;
cassert(x == 12); // 여기서 실패
}
int main() { test(); }
```
이 예에서는 상수 표현식에서 사용할 수 없는 함수를 즉시 함수가 호출했기 때문에 컴파일이 실패한다. 즉, 어설션(assertion)이 실패한 후 컴파일이 중지된다.
일반적인 컴파일 오류 메시지는 다음과 같다.
```cpp
In function 'int main()':
in 'constexpr' expansion of 'test()'
in 'constexpr' expansion of 'cassert(x == 12)'
error: call to non-'constexpr' function 'you_see_this_error_because_assertion_fails()'
you_see_this_error_because_assertion_fails();
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~
[ ... ]
```
다음은 컴파일 타임 인수 검사를 가능하게 하는 생성자로서 즉시 함수를 사용하는 또 다른 예이다.
```cpp
#include
#include
void you_see_this_error_because_the_message_ends_with_exclamation_point() {}
struct checked_message {
std::string_view msg;
consteval checked_message(const char* arg)
: msg(arg) {
if (msg.ends_with('!'))
you_see_this_error_because_the_message_ends_with_exclamation_point();
}
};
void send_calm_message(checked_message arg) {
std::cout << arg.msg << '\n';
}
int main() {
send_calm_message("Hello, world");
send_calm_message("Hello, world!");
}
```
여기서 컴파일은 다음과 같은 메시지와 함께 실패한다.
```cpp
In function 'int main()':
in 'constexpr' expansion of 'checked_message(((const char*)"Hello, world!"))'
error: call to non-'constexpr' function 'void you_see_this_error_because_the_message_ends_with_exclamation_point()'
you_see_this_error_because_the_message_ends_with_exclamation_point();
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~
[ ... ]
4. 다른 프로그래밍 언어에서의 CTFE
D 언어와 Zig 프로그래밍 언어 등 다양한 프로그래밍 언어에서 컴파일 타임 함수 실행(CTFE) 기능을 지원한다.
4. 1. D 언어
D 언어에서는 `enum`을 이용하여 컴파일 타임에 함수를 실행하고, 그 결과를 변수에 할당할 수 있다.[3]```D
int factorial(int n) {
if (n == 0)
return 1;
return n * factorial(n - 1);
}
// 컴파일 타임에 계산됨
enum y = factorial(0); // == 1
enum x = factorial(4); // == 24
```
위 예시는 일반적으로 런타임에 평가되는 "factorial"이라는 유효한 D 함수를 보여준다. `enum`을 사용하면 변수의 초기화 값이 컴파일 시간에 계산되어야 함을 컴파일러에게 알려준다. 함수의 인수는 컴파일 시점에 결정될 수 있어야 한다.[4]
CTFE를 사용하면 간단한 방법으로 컴파일 시간에 데이터 구조를 채울 수 있다. (D 버전 2):
```D
int[] genFactorials(int n) {
auto result = new int[n];
result[0] = 1;
foreach (i; 1 .. n)
result[i] = result[i - 1] * i;
return result;
}
enum factorials = genFactorials(13);
void main() {}
// '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 코드로 구문 분석되고 컴파일된다.
4. 2. Zig 언어
Zig 프로그래밍 언어에서 컴파일 타임 함수 실행의 예시는 다음과 같다.[5]```Zig
pub fn factorial(n: usize) usize {
var result = 1;
for (1..(n + 1)) |i| {
result *= i;
}
return result;
}
pub fn main() void {
const x = comptime factorial(0); // == 0
const y = comptime factorial(4); // == 24
}
```
위 예시는 일반적으로 런타임에 평가될 "factorial"이라는 유효한 Zig 함수를 지정한다. `comptime`을 사용하면 변수의 초기화가 컴파일 시간에 계산되어야 함을 컴파일러에 알린다. 함수의 인수는 컴파일 시간에 해결할 수 있어야 한다.
Zig는 또한 컴파일 타임 매개변수를 지원한다.[6]
```Zig
pub fn factorial(comptime n: usize) usize {
var result: usize = 1;
for (1..(n + 1)) |i| {
result *= i;
}
return result;
}
pub fn main() void {
const x = factorial(0); // == 0
const y = factorial(4); // == 24
}
```
컴파일 타임 함수 실행(CTFE)은 컴파일 시간에 제네릭 데이터 구조를 만드는 데 사용할 수 있다.
```Zig
fn List(comptime T: type) type {
return struct {
items: []T,
len: usize,
};
}
// The generic List data structure can be instantiated by passing in a type:
var buffer: [10]i32 = undefined;
var list = List(i32){
.items = &buffer,
.len = 0,
};
참조
[1]
웹사이트
Reflective Metaprogramming in C++
http://www.open-std.[...]
2003-04-18
[2]
웹사이트
General Constant Expressions for System Programming Languages. SAC-2010. The 25th ACM Symposium On Applied Computing.
http://www.stroustru[...]
2010-03
[3]
문서
D 2.0 language specification: Functions
http://d-programming[...]
[4]
문서
D 2.0 language specification: Attributes
http://d-programming[...]
[5]
문서
Zig 0.11.0 Language Reference: Compile-Time Expressions
https://ziglang.org/[...]
[6]
문서
Zig 0.11.0 Language Reference: Compile-Time Parameters
https://ziglang.org/[...]
[7]
웹인용
Reflective Metaprogramming in C++
http://www.open-std.[...]
2003-04-18
[8]
웹인용
General Constant Expressions for System Programming Languages. SAC-2010. The 25th ACM Symposium On Applied Computing.
http://www.stroustru[...]
2010-03
본 사이트는 AI가 위키백과와 뉴스 기사,정부 간행물,학술 논문등을 바탕으로 정보를 가공하여 제공하는 백과사전형 서비스입니다.
모든 문서는 AI에 의해 자동 생성되며, CC BY-SA 4.0 라이선스에 따라 이용할 수 있습니다.
하지만, 위키백과나 뉴스 기사 자체에 오류, 부정확한 정보, 또는 가짜 뉴스가 포함될 수 있으며, AI는 이러한 내용을 완벽하게 걸러내지 못할 수 있습니다.
따라서 제공되는 정보에 일부 오류나 편향이 있을 수 있으므로, 중요한 정보는 반드시 다른 출처를 통해 교차 검증하시기 바랍니다.
문의하기 : help@durumis.com