C++ 템플릿 vs C# 제네릭
프로그래밍 언어에서 제네릭 프로그래밍(Generic Programming)은 코드를 보다 유연하고 재사용 가능하게 만드는 중요한 기법이다. C++와 C#은 각각의 방식으로 제네릭 프로그래밍을 지원하는데, C++에서는 템플릿(Templates)이라는 개념을, C#에서는 제네릭(Generics)이라는 개념을 사용한다. 이 두 가지 개념은 비슷해 보이지만, 그 구현 방식과 작동 원리에는 차이가 있다. 이번 글에서는 C++의 템플릿과 C#의 제네릭을 비교해 알아보겠다.
C++ template :
C++ 템플릿은 함수나 클래스를 작성할 때, 특정 데이터 타입에 구애받지 않고
다양한 타입을 사용할 수 있하여 코드 재사용성을 크게 높힌다.
template <typename T>
T add(T a, T b) {
return a + b;
}
int main() {
int resultInt = add(3, 4); // int 타입으로 사용
double resultDouble = add(3.5, 2.5); // double 타입으로 사용
}
위 코드에서 add 함수는 int, float, double 등 다양한 타입의 덧셈을 처리할 수 있습니다. C++ 컴파일러는 템플릿을 사용하여 특정 타입에 맞게 코드를 생성한다. 이를 템플릿 인스턴스화(Template Instantiation)라고 한다.
특징:
컴파일 타임: 템플릿은 컴파일 타임에 인스턴스화되어 실행 속도가 빠르지만 컴파일 시간이 길어질 수 있다.
타입 안전성: 템플릿은 컴파일 타임에 타입 검사를 수행하므로, 타입 안전성을 보장한다.
유연성: 다양한 타입과 복잡한 데이터 구조를 지원한다.
C# generic
C# 제네릭은 컴파일 타임과 런타임에 모두 타입 안전성을 제공하며, 주로 컬렉션과 같은 데이터 구조에서 사용된다.
using System;
using System.Numerics;
public class Program
{
public static T Add<T>(T a, T b) where T : INumber<T>
{
return a + b;
}
public static void Main()
{
int resultInt = Add(3, 4); // int 타입으로 사용
double resultDouble = Add(3.5, 2.5); // double 타입으로 사용
}
}
C#에서 제네릭 메서드와 클래스는 런타임에 타입 정보가 유지되며,
이는 주로 JIT(Just-In-Time) 컴파일러가 실행 시 최적화한다.
특징:
런타임: C# 제네릭은 런타임에 타입 정보가 유지되므로, 리플렉션과 같은 기능을 사용할 수 있다.
타입 안전성: 제네릭은 런타임과 컴파일 타임에 모두 타입 검사를 수행하여 타입 안전성을 보장한다..
상속 및 인터페이스: 제네릭 타입은 상속과 인터페이스 구현에서 강력한 유연성을 제공한다.
Template과 Generic의 차이
1. 컴파일
C++ template : 컴파일 시점에 모든 타입이 결정되고, 타입별로 코드가 생성
C# generic : 컴파일 타임에 타입 검사*를 수행하며, 런타임에도 타입 정보가 유지되어 JIT 컴파일러가 최적화된 코드를 생성
2. 타입 제약
C++ template : 명시적인 타입 제약 조건이 없음
C# generic : 타입 메개변수에 대해 제약 조건을 명시적으로 지정 가능
3. 상속 및 다형성
C++ template : 템플릿이 인스턴스화된 후에만 상속 계층 구조 결정
C# generic : 타입 매개변수가 지정되기 전에 상속 계층 구조를 명확하게 정의 가능
4. 타입 소거** vs 타입 인스턴스화***
C++ template : 타입 인스턴스화를 사용하여 각 타입에 대해 별도의 클래스/함수 인스턴스를 생성
C# generic : 타입 소거 방식을 사용하여 런타임에 타입 정보를 유지
5. 유연성과 타입 독립성:
C++ template : 매우 유연하며 복잡한 타입 매핑과 메타프로그래밍을 지원
C# generic : 타입 안전성과 편리성을 중시하며, 상속과 인터페이스 구현에서 유연성을 제공
사용 용도:
C++ template : 고성능 시스템 프로그래밍, 복잡한 데이터 구조와 알고리즘 구현 등에 사용
C# generic : 비즈니스 애플리케이션, 데이터베이스 연동, 웹 애플리케이션 등에서 널리 사용
*컴파일 타임 타입 검사
제네릭을 사용하는 코드가 컴파일될 때, 컴파일 타입 매개 변수가 올바르게 사용되는지 확인
public class GenericClass<T>
{
public void PrintType(T param)
{
// 컴파일 타임에 param이 T 타입인지 확인
Console.WriteLine(param.GetType());
}
}
public class Program
{
public static void Main()
{
GenericClass<int> intInstance = new GenericClass<int>();
intInstance.PrintType(5); // 정상 컴파일
GenericClass<string> stringInstance = new GenericClass<string>();
stringInstance.PrintType("Hello"); // 정상 컴파일
// GenericClass<int> intInstanceError = new GenericClass<int>();
// intInstanceError.PrintType("Hello"); // 컴파일 오류: 타입 불일치
}
}
** 타입 소거 (Type Erasure) : 컴파일러가 제네릭 타입 정보를 제거하고 구체적인 타입으로 변환하는 과정
*** 타입 인스턴스화 (Type Instantiation) : 컴파일러가 제네릭 타입을 실제로 사용할 때 각기 다른 타입에 대해 별도의 코드 인스턴스를 생성하는 과정, 여러 타입에 대해 각각 코드가 생성되므로 코드 크기가 증가할 수 있음
언리얼의 TArray에서 사용된 template
참고 링크:
'C++' 카테고리의 다른 글
#include <memory> Smart Pointer (0) | 2024.07.01 |
---|---|
Struct vs Class (0) | 2024.06.20 |
SOLID - OOP 설계의 원칙 (0) | 2024.06.08 |
OOP - Object Oriented Programming 객체 지향 프로그래밍 (0) | 2024.06.03 |
std::sort() & Lamda (0) | 2024.05.14 |