흔한 덕후의 잡동사니

C++ 템플릿과 C# 제네릭의 차이점 본문

언어 관련/C#

C++ 템플릿과 C# 제네릭의 차이점

chinodaiski 2025. 2. 11. 22:48

C#의 제네릭(Generic)과 C++의 템플릿(Template)은 모두 타입에 독립적인 코드를 작성할 수 있도록 해주는 기능이지만, 구현 방식과 동작 원리에서 차이점이 있다.

 

1. 컴파일 시점 vs 런타임 시점

[ C++ Template ] 

C++ 템플릿은 컴파일 시점에 인스턴스화된다. 

컴파일러는 템플릿 코드를 사용하는 각 타입에 대해 별도의 코드를 생성한다. 예를 들어, std::vector<int>와 std::vector<double>은 컴파일 시점에 서로 다른 코드로 생성된다.

컴파일 시점에 생성된 템플릿


이로 인해 템플릿은 컴파일 시간에 타입 검사를 수행하며, 잘못된 타입이 사용되면 컴파일 오류가 발생한다.

[ C# Generic ]
C#의 제네릭은 런타임 시점에 인스턴스화된다.

 

제네릭 코드는 컴파일 시점에 중간 언어(IL)로 컴파일되고, 런타임에 JIT(Just-In-Time) 컴파일러에 의해 실제 타입으로 치환된다.
이로 인해 제네릭은 런타임에 타입 검사를 수행하며, 모든 타입에 대해 동일한 코드를 재사용한다.

 

중간 언어로 컴파일 되는 과정은 이전 글을 참고하자.

https://hellowcode.tistory.com/entry/IL2CPP-Mono-AOT-JIT-%EA%B0%9C%EB%85%90-%EC%A0%95%EB%A6%AC

 

 

2. 코드 생성 방식

[ C++ Template ] 
템플릿은 각 타입에 대해 별도의 코드를 생성한다. 이로 인해 템플릿을 사용하면 코드가 구체화되는 과정을 통해 바이너리 크기가 커진다.

[ C# Generic ]
제네릭은 모든 타입에 대해 동일한 코드를 공유한다. 예를 들어, List<int>와 List<double>은 동일한 IL 코드를 사용하며, 런타임에 타입이 결정된다. 이로 인해 메모리 사용량이 줄어들고, 바이너리 크기가 작아진다.

 

 

3. 타입 안전성

[ C++ Template ] 
템플릿은 컴파일 시점에 타입 검사를 수행하므로, 잘못된 타입이 사용되면 컴파일 오류가 발생한다. 하지만 템플릿은 타입에 따라 다른 코드를 생성할 수 있기 때문에, 타입에 따라 동작이 달라질 수 있다. 예를 들어 부분 특수화 같은 방법을 사용할 수 있다.

[ C# Generic ]
제네릭은 런타임에 타입 검사를 수행하므로, 잘못된 타입이 사용되면 런타임 오류가 발생할 수 있다. 하지만 타입에 대해 동일한 코드를 재사용하므로, 타입에 따라 동작이 달라지지 않는다. 부분 특수화가 허용되지 않는 이유이다.

 

 

4. 타입 제약

[ C++ Template ] 
템플릿은 타입에 대한 제약을 명시적으로 지정할 수 없다. 대신, 템플릿 내에서 사용되는 연산자나 메서드가 타입에 존재하지 않으면 컴파일 오류가 발생한다. 간단히 생각하면 컴파일 타임에 오류를 전부 잡아준다고 생각하면 쉽다. 예를 들어, 덧셈 연산이 있을 경우, <T> 타입에 + 연산자가 정의되어 있지 않으면 컴파일 오류가 발생한다.

[ C# Generic ]
제네릭은 where 절을 사용하여 타입에 대한 제약을 명시적으로 지정할 수 있다. 예를 들어, where T : IComparable과 같이 제약을 추가하여 특정 인터페이스나 클래스를 구현한 타입만 사용하도록 제한할 수 있다. 이는 뭔가를 추가하는 부분 특수화 같은 방법이 아니라, 기존 방식에서 제한을 가한 것이다.

 

 

5. 성능

[ C++ Template ] 

템플릿은 컴파일 시점에 코드가 생성되기 때문에, C#에 비해 상대적으로 런타임 성능이 좋다. 
하지만 컴파일 시간이 길어져 개발 과정에서 시간이 오래걸리고, 바이너리 크기가 커져 exe 파일의 크기가 커진다.

[ C# Generic ]
제네릭은 런타임에 타입이 결정되기 때문에, C++ 템플릿에 비해 컴파일 시간이 짧고 바이너리 크기가 작다.
하지만 런타임에 타입을 확인하는 오버헤드가 존재한다.

 

 


6. 사용 사례

[ C++ Template ] 

템플릿은 매우 유연하며, 컴파일 시점에 최적화가 가능하다. 그렇기에 STL(Standard Template Library)과 같은 템플릿 기반의 상대적인 고성능 라이브러리를 구현하는 데 적합하다.

[ C# Generic ]
제네릭은 타입 안전성과 코드 재사용성을 높이는 데 적합하다. 이는 크로스 플랫폼을 기반으로 한 .NET 프레임워크의 특성을 기반으로 .NET 컬렉션(List<T>, Dictionary<TKey, TValue> 등)과 같은 범용 라이브러리를 구현하는 데 주로 사용된다.

 

 

7. 요약

C++ 템플릿은 고성능과 유연성이 중요한 경우에 적합하고, C# 제네릭은 타입 안전성과 코드 재사용성이 중요한 경우에 적합하다. 이는 어디까지나 상대적인 관점이고, 게임 제작시 C#을 주로 사용하는 Unity에서도 IL2CPP라는 기능을 지원하고 있기에 최종적인 성능은 비슷하게 나오고 있다. 물론 환경에 따라 다르기에 정확한 성능은 테스트를 해봐야 한다.

 

 

참고

MSDN 문서(C++ 템플릿과 C# 제네릭의 차이점(C# 프로그래밍 가이드))

https://learn.microsoft.com/vi-vn/dotnet/csharp/programming-guide/generics/differences-between-cpp-templates-and-csharp-generics