연산자 오버로딩과 제네릭 — 특수화 시점의 연산 가능성
연산자 오버로딩과 제네릭 — 특수화 시점의 연산 가능성
연산자 오버로딩(15장, 846페이지)과 제네릭은 밀접하게 관련돼 있어요. 다음 정의를 가진 제네릭 클래스를 상상해 보세요.
출처: Operator overloading and generics — Free Pascal Reference
본문
{$mode objfpc}
unit mya;
interface
type
Generic TMyClass<T> = Class(TObject)
Function Add(A,B : T) : T;
end;
Implementation
Function TMyClass.Add(A,B : T) : T;
begin
Result:=A+B;
end;
end.
컴파일러가 제네릭 매크로를 재생할 때 덧셈이 가능해야 해요. 다음과 같은 특수화는:
TMyIntegerClass = specialize TMyClass<integer>;
문제가 없어요. Add 메서드는 다음과 같이 되기 때문이에요.
Procedure TMyIntegerClass.Add(A,B : Integer) : Integer;
begin
Result:=A+B;
end;
컴파일러는 정수 두 개를 더하는 방법을 알기 때문에 이 코드는 문제없이 컴파일돼요. 하지만 다음 코드는:
Type
TComplex = record
Re,Im : Double;
end;
Type
TMyIntegerClass = specialize TMyClass<TComplex>;
두 TComplex 타입의 덧셈이 정의돼 있지 않으면 컴파일되지 않아요. 이것은 레코드 연산자로 해결할 수 있어요.
{$modeswitch advancedrecords}
uses mya;
Type
TComplex = record
Re,Im : Double;
class operator +(a,b : TComplex) : TComplex;
end;
class operator TComplex.+ (a,b : TComplex) : TComplex;
begin
Result.re:=A.re+B.re;
Result.im:=A.im+B.im;
end;
Type
TMyComplexClass = specialize TMyClass<TComplex>;
begin
// Code here
end.
현재, 구현 제약 때문에 전역 연산자를 사용해서는 동작하지 않아요. 즉 다음은 아직 동작하지 않아요.
uses mya;
Type
TComplex = record
Re,Im : Double;
end;
operator + (a,b : TComplex) : TComplex;
begin
Result.re:=A.re+B.re;
Result.im:=A.im+B.im;
end;
Type
TMyComplexClass = specialize TMyClass<TComplex>;
begin
// Code here
end.
이 구조에 대한 지원은 Free Pascal의 향후 버전에서 예상돼요.
핵심은 이거예요. 제네릭 안의 A+B 같은 연산은 컴파일러가 그 타입에 대한 연산자를 알고 있을 때만 성립해요. 기본 타입은 컴파일러가 내장 연산을 알고 있지만, 사용자 정의 타입(레코드 등)은 해당 타입에 대한 연산자 오버로딩이 있어야 해요. 그리고 현재 FPC에서는 레코드 연산자(class operator)로 특수화 타입의 연산을 정의해야 동작한다는 점을 기억하세요.
더 알아보기
- 레코드 연산자에 대한 자세한 내용은 Record operators를 참고하세요
- 제네릭의 이름 가시성 규칙은 A word about scope에서 다뤄요