연산자 오버로딩과 제네릭 — 특수화 시점의 연산 가능성

연산자 오버로딩과 제네릭 — 특수화 시점의 연산 가능성

연산자 오버로딩(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)로 특수화 타입의 연산을 정의해야 동작한다는 점을 기억하세요.

더 알아보기