C++ Template, Expression Templates #3

Short Articles 2012. 2. 21. 22:50
표현식 템플릿은 숫자 배열 클래스를 지원하기 위해 고안된 프로그램이 기술입니다
이번 아티클은 다음과 같이 진행합니다
1. 단순한 배열 클래스 구현하여 배열 연산에 대한 문제제기
2. 표현식 템플릿 구현
3. 표현식 템플릿을 아는 랩퍼클래스 구현
4. 실재 표현식 템플릿 사용해서 어떻게 동작하는 방법 추적

전체 표현식을 다 읽기 전에는 표현식의 일부만 계산하지 않고 전체 계산하기전에 어떤 객체에 무슨 연산이 적용되었는지 기록하는 것이 표현식 템플릿의 핵심입니다 

첫시간에 SArray 단순 배열 클래스를 만들었습니다
A_Add, A_Mult, A_Scalar에 대해서 배웠습니다
(스칼라 때문에 A_Traits 이라는 특질클래스도 배웠습니다)

이것을 가지고는 표현식 템플릿을 할 수 없습니다
이 표현식 템플릿을 알고 있는 랩퍼클래스 Array 만들어야 합니다

template <typename T, typename Rep = SArray<T> >
class Array;

Array가 값을 저장하는 실제 배열일 경우 SArray가 되며 A_Add나 A_Mult처럼 표현식을 나타낼 경우에는 중첩된 템플릿 식별자가 될 수도 있다

많은 연산들이 Rep 객체에 전달되기만 한다

이제 연산자를 구현해보자 이제부터 어려운 부분 시작입니다 정신을 똑바로 차리시고 코드에 집중해 주세요
두 배열의 덧셈입니다

복잡합니다 ㅠㅠ
템플릿
template <typename T, typename R1, typename R2>
T는 자료형이고요 R1, R2는 실제 배열클래스입니다 여기서는 SArray가 되겠죠?

리턴타입은 Array<T,A_Add<T,R1,R2> >
Array인데 자료형은 T이고 실재저장형은 A_Add<T,R1,R2> 인데
이것은 A_Add<T,R1,R2>은 R1,R2 저장한 결과 담고 있는 배열 이라고 생각해도 된다고 했죠
실재 저장한것이 아니라 R1과 R2 객체에 덧셈연산을 적용되었다고 기록하는 것입니다
앞서 말씀드렸지만 [] 연산자를 호출할때 그때 저장해서 값을 리턴합니다
하지만 여기서 수식이 복잡해지므로 우선 저장한 결과를 담은 배열이라고 생각합시다

함수명 operator+ 연산자 오버로딩 했습니다 C++ 기본 기능

함수인자
Array<T,R1> const& a
Array<T,R2> const& b
앞서 말씀드렸지만 R1, R2는 실제 저장 배열클래스입니다 여기서는 SArray 타입입니다
a는 자료형 T 실재배열 클래스 R1 값을 가지고 있는 레퍼클래스 Array의 객체 입니다
b도 마찬가지 입니다

리턴문 Array<T,A_Add<T,R1,R2> > (A_Add<T,R1,R2>(a.rep(),b.rep()));
가장 난해하면서 핵심 입니다
먼저 A_Add<> 객체를 생성 합니다
A_Add<T,R1,R2>(a.rep(),b.rep())
a.rep() 실재 저장된 배열 클래스를 반환하는 연산자 입니다
A_Add<T,R1,R2> 는 클래스 명이고요 
A_Add<T,R1,R2>(a.rep(),b.rep())은  A_Add<T,R1,R2>클래스의 생성자 호출 입니다
그 다음에 리턴 타입 객체를 생성합니다
Array<T,A_Add<T,R1,R2> > 은 클래스 명 입니다
Array<T,A_Add<T,R1,R2> > (A_Add<T,R1,R2>(a.rep(),b.rep()))은 클래스 생성자 호출 입니다
템플릿이 들어가서 한눈에 알아보기가 힘들지만 어쨌든 생성자를 호출해서 리턴 합니다
Array를 리턴타입으로 사용하는 이유는  Array객체로 래핑해 배열의 데이터를 나타내는  다른 객체와 같이 사용할 수 있게 하는 것입니다
리턴된  Array<T,A_Add<T,R1,R2> > 객체가 다른 Array객체와  operator+ 연산이 가능해 집니다

다음은 배열 곱셈연산입니다

배열 덧셈연산과 동일한 과정을 거치므로 설명을 생략합니다
다음은 스칼라와 배열 곱셈 입니다

자~ 설명 들어갑니다 
템플릿
 template <typename T, typename R2>
T는 자료형, R2는 실재 저장 배열 클래스 여기서는 SArray 입니다

리턴타입 Array<T, A_Mult<T,A_Scalar<T>,R2> >
Array 인데 T는 자료형  A_Mult<T,A_Scalar<T>,R2> 저장배열
A_Mult<T,A_Scalar<T>,R2>는 A_Scalar<T>와 R2를 곱한 결과를 담는 배열
A_Scalar<T> 는 모두 같은 값이 배열 이고요

함수명 operator* 연산자 오버로딩

함수인자
T const& s 평범한 값
Array<T,R2> const& b R2를 실재 저장클래스로 갖고 있는 레퍼배열 클래스

리턴값 Array<T,A_Mult<T,A_Scalar<T>,R2> > (A_Mult<T,A_Scalar<T>,R2>(A_Scalar<T>(s), b.rep()));
먼저 s를 스칼라로 변경합니다
A_Scalar<T>(s) 스칼라 생성자 호출
두 배열을 곱셈 합니다
A_Mult<T,A_Scalar<T>,R2> 클래스 형
A_Mult<T,A_Scalar<T>,R2>(A_Scalar<T>(s), b.rep() ) 생성자 호출
리턴타입  Array<T,A_Mult<T,A_Scalar<T>,R2> >  
Array<T,A_Mult<T,A_Scalar<T>,R2> > (A_Mult<T,A_Scalar<T>,R2>(A_Scalar<T>(s), b.rep()));  생성자 호출
리턴된 Array<T,A_Mult<T,A_Scalar<T>,R2> > 객체는 다른 Array객체와 연산이 가능해 집니다

다음번은 실재 값을 사용해서 효율적인지 확인 해보겠습니다
 
: