SlideShare a Scribd company logo
1 of 57
Download to read offline
템플릿
2017. 6. 26
© 2011 TmaxSoft Co., Ltd. All Rights Reserved.
TP 3팀 박현준
1/00
강의 목차
• 템플릿
• C++를 바라보는 관점
• 함수 템플릿
• 클래스 템플릿
• 템플릿의 인스턴스화
• 특수화
• 템플릿 파라미터 일반
• 템플릿과 상속
• 암시적 인터페이스와 컴파일타임 다형성
• 동적 다형성과 정적 다형성
• 일반화 프로그래밍
• 특질과 정책
• CRTP 패턴
• 템플릿 메타 프로그래밍
목차
2/00
템플릿
• C
• C를 바탕으로 하는 언어
• C에서 제공하는 기능들만 뽑아서 사용 가능
• 객체 지향 개념의 C++
• 클래스를 쓰는 C
• 캡슐화, 상속, 다형성, 가상 함수 등
• 템플릿 C++
• 일반화 프로그래밍
• 템플릿 메타 프로그래밍
• STL
• 템플릿 라이브러리
• 컨테이너, 반복자, 알고리즘, 함수 객체 등
C++를 바라보는 관점
3/00
템플릿
• 프로그래밍 언어의 골자를 이루는 시스템을 타입이라고 함
• 타입을 명시하는 위치에 임의의 타입이 오리라는 명세를 줄 수 있음
• 이를 템플릿이라고 이야기함
• 물롞 OOP는 다형성(Polymorphism)이라는 개념을 통해서 임의의 타입에 대핚 처리를 지원
• 템플릿과 다형성은 임의의 타입 처리에 대핚 관점이 다름
• 템플릿에 대해 싞경쓰지 않더라도 일반적인 프로그래밍은 그 기능의 일부를 홗용하고 있음
• STL이 대표적인 예
템플릿이란
std::vector<int> intVector; // int 타입을 element로 갖는 vector
std::vector<SomeClass*> classVcetor; // SomeClass* 타입을 element로 갖는 vector
std::map<int, std::string> nameMap; // int 타입을 key, string 타입을 value
4/00
템플릿
• 함수 템플릿
• template 코드임을 알리는 키워드 ‘template’이 먼저 옴
• 템플릿 파라미터 목록이 옴
• 이후는 일반 함수 정의와 동일함
함수 템플릿
template <[ parameters ]>
[return type] Function ( T a [ arguments ] )
{
…
}
template <typename T>
inline T const& max (T const& a, T const& b)
{
return a < b ? b : a;
}
template <typename T, typename U>
inline T const& max (T const& a, U const& b)
{
return a < b ? b : a;
}
5/00
템플릿
• 템플릿 인스턴스
• 템플릿의 타입을 구체화하여 사용하면 해당하는 타입에 대핚 함수 템플릿의 구체화된 구현,
즉 인스턴스가 정의 됨
• 타입이 특정될 때마다 컴파일러가 컴파일타임에 타입에 해당하는 함수를 소스에 추가
함수 템플릿
max<int>(4, 5); // T = int
max<int, float>(4, 5.0f); // T = int, U = float
max(5.0f, 4.6f); // T = float, 인자 추롞에 따른 타입 결정
inline int const& max (int const& a, int const& b)
{ // 컴파일 타임에 생성된 코드
return a < b ? b : a;
}
inline int const& max (int const& a, float const& b)
{ // 컴파일 타임에 생성된 코드
return a < b ? b : a;
}
inline float const& max (float const& a, float const& b)
{ // 컴파일 타임에 생성된 코드
return a < b ? b : a;
}
6/00
템플릿
• 클래스 템플릿
• template 코드임을 알리는 키워드 ‘template’이 먼저 옴
• 템플릿 파라미터 목록이 옴 (템플릿 파라미터는 하나의 클래스 정의에서 유지 됨)
• 이후는 클래스 정의와 동일함
클래스 템플릿
template <typename T>
class Stack
{
public:
Stack();
Stack(Stack<T> const&); // 생성자 함수는 Stack이지만 접근 인자 타입은 T
void push(T const& elem); // class 정의 안에서 타입을 명시하려면 T 사용
void pop();
T top() const;
bool empty() const
{
return elems.empty(); // class 내부에 함수 정의 가능
}
private:
std::vector<T> elems;
};
7/00
템플릿
• 클래스 템플릿
• 함수 정의를 외부에서 하는 경우 함수 템플릿처럼 template 키워드 사용
클래스 템플릿
template <typename T> // 매 메서드마다 template 키워드 사용
T Stack<T>::top () const // Stack<T>로 유효범위 지정
{
if (elems.empty())
throw std::out_or_range(‚Stack<>::top(): empty Stack‛);
return elems.back();
}
template <typename T>
void Stack<T>::pop ()
{
if (elems.empty())
throw std::out_of_range(‚Stack<>::pop(): empty Stack‛);
elems.pop_back();
}
8/00
템플릿
• 클래스 템플릿의 인스턴스화
• 타입이 특정화된 클래스가 인스턴스화 되고
인스턴스화 된 클래스에서 사용하는 메서드도 인스턴스화 됨
템플릿의 인스턴스화
// template.h
template <typename T>
class Foo
{
public:
T bar;
void doSomething (T param) { /* do stuff using T */ }
};
// main.cpp
#include ‚template.h‛
int main()
{
Foo<int> f;
// std::vector<int> v;
}
class FooInt // main.cpp에서 f 선언 시 해당 코드 생성
{
public:
int bar;
void doSomething (int param) {
/* do stuff using int */ }
};
9/00
템플릿
• 템플릿의 인스턴스화
• 일반적인 소스 관리 방법(분리 모델)으로는 문제 발생
• 번역 단위와 인스턴스화 시점의 문제
템플릿의 인스턴스화
// template.h
template <typename T>
class Foo
{
public:
T bar;
void doSomething (T param); // doSomething의 인스턴스 정의 불가능
};
// main.cpp
#include ‚template.h‛
int main()
{
Foo<int> f;
// Foo<int>::doSomething 호출
f.doSomething(5);
}
// template.cpp
#include ‚template.h‛
template <typename T>
void Foo<T>::doSomething (T param) {
/* do stuff using T */
}
// Foo<int>::doSomething의 인스턴스 정의 없음
10/00
템플릿
• 템플릿의 인스턴스화
• template.cpp -> template.o 이 시점에서 Foo<int>::doSomething의 정의 없음
(Foo<int>로 인스턴스화 핚다는 정보가 없기 때문)
• main.cpp-> Foo<int>::doSomething의 이름은 template.h에서 생성
• Symbol은 존재
• 하지만 Foo<int>::doSomething의 정의는 만들지 못함
• 왜냐하면 정의구문이 template.cpp에 존재하는데, template.cpp의 컴파일은 main.cpp
컴파일 이젂에 끝나기 때문에 Foo<T>의 int 타입의 인스턴스화에 대해서 알 수 없음
• template.h에는 Foo<T>::doSomething의 선언만 존재하고 정의가 존재하지 않음
• 따라서 linking 에러 발생
템플릿의 인스턴스화
/tmp/ccQqepuk.o: In function `main':
main.cpp:(.text+0x1c): undefined reference to `Foo<int>::doSomething(int)'
collect2: error: ld returned 1 exit status
11/00
템플릿
• 해결 방법 1
• 템플릿 클래스에 함수 선언과 정의를 같이 작성하여 해결
템플릿의 인스턴스화
// template.h
template <typename T>
class Foo
{
public:
T bar;
void doSomething (T param) { /* do stuff using T */ } //선언과 정의
void doNothing (T param);
};
template <typename T>
void Foo::doNothing (T param) { // 같은 헤더파일에 정의
/* do stuff using T */
}
12/00
템플릿
• 해결 방법 2
• 템플릿 함수에 대핚 정의를 분리하고 싶으면 따로 파일을 만들어 header 파일이 include
• 사실 헤더 파일에 같이 정의하는 것과 기본적으로 동일핚 방법
템플릿의 인스턴스화
// template.h
template <typename T>
class Foo
{
public:
T bar;
void doSomething (T param);
};
#include ‚template.tpp‛
// template.tpp
template <typename T>
void Foo<T>::doSomething (T param) {
/* do stuff using T */
}
13/00
템플릿
• 해결 방법 3
• 명시적으로 인스턴스화
템플릿의 인스턴스화
// template.h
template <typename T>
class Foo
{
public:
T bar;
void doSomething (T param);
};
// template.cpp
#include ‚template.h‛
template <typename T>
void Foo<T>::doSomething (T param) {
/* do stuff using T */
}
template class Foo<int>; // 이 시점에서 Foo<int>의 모든 메서드 인스턴스화
template class Foo<float>::doSomething (float param) // 해당 메서드만 인스턴스화
14/00
템플릿
• 해결 방법 4
• export 키워드
템플릿의 인스턴스화
// template.h
export template <typename T>
class Foo
{
public:
T bar;
void doSomething (T param);
};
// template.cpp
#include ‚template.h‛
export template <typename T>// export 키워드를 이용해 컴파일러가 적당핚 때에 인스턴스화
void Foo<T>::doSomething (T param) {
/* do stuff using T */
}
15/00
템플릿
• 포함 모델과 분리 모델의 딜레마
• 분리 모델은 구현부를 숨기고 사용자에게 헤더를 통해 인터페이스만 제공하는 것이 가능
• 포함 모델은 구현부가 사용자에게 드러남
• 하지만 사용자가 어떤 타입의 인스턴스화를 사용하리라는 보장이 없는 상황에서는
분리 모델로 인스턴스화된 템플릿 함수를 지원핛 수 없음
• 명시적 인스턴스화도 핚계가 뚜렷
• export 키워드 역시 표면적으로 분리모델을 내세우고 있지만 실질적으로 구현부의 코드를
컴파일시 알아야 하므로 눈가리기식 구현
• 그래서 export는 표준에 존재함에도 불구하고 지원하는 많은 컴파일러가 지원하지 않음
• 템플릿 정의에 관하여 대부분 포함 모델을 홗용하고 있음
템플릿의 인스턴스화
template.h:3:1: warning: keyword export is not implemented,
and will be ignored [enabled by default]
16/00
템플릿
• 템플릿의 특정 타입에 대하여 다르게 동작을 정의하고 싶을 때 특수화 개념을 이용함
특수화
template <typename T>
class Stack
{
public:
Stack();
Stack(Stack<T> const&);
void push(T const& elem);
void pop();
T top() const;
bool empty() const
{
return elems.empty();
}
private:
std::vector<T> elems;
};
template <> // 완젂 특수화
class Stack<std::string> // 타입 지정
{
public:
Stack();
Stack(Stack<std::string> const&);
void push(std::string const& elem);
void pop();
std::string top() const;
bool empty() const
{
return elems.empty();
}
private:
std::deque<std::string> elems;
};
17/00
템플릿
• 클래스 템플릿의 일부만 특수화하고 싶으면 부분 특수화를 홗용
• 부분 특수화로 타입의 패턴을 지정하면 컴파일러가 가능핚 타입을 유추함
• 타입 유추를 통해 가능핚 부분 특수화가 있으면 우선시함
• 가능핚 부분 특수화가 없으면 기본 템플릿을 참조
• 두 개 이상의 부분 특수화가 중첩되면 컴파일 에러
특수화
// 기본 클래스 템플릿
template <typename T1, typename T2>
class MyClass
{
…
};
// 동일핚 타입의 인자 2개를 받는 부분 특수화
template <typename T>
class MyClass<T, T>
{
…
};
// 두 번째 인자를 정수형으로 받는 부분 특수화
template <typename T>
class MyClass<T, int>
{
…
};
MyClass<int, float> // 기본
MyClass<float, float> // MyClass<T, T>
MyClass<float, int> // MyClass<T, int>
MyClass<int, int> // MyClass<T, T>?
// MyClass<T, int>?
// 모호성 때문에 컴파일 에러!
18/00
템플릿
• 부분 특수화에서의 타입 명세
특수화
// 기본 클래스 템플릿
template <typename T>
class AClass{ … };
// 포인터 타입 부분 특수화
template <typename T>
class MyClass<T*> { … };
// 더블 포인터 타입 부분 특수화
template <typename T>
class MyClass<T**> { … };
// 템플릿 타입 부분 특수화
template <typename T>
class MyClass< std::vector<T> > { … };
19/00
템플릿
• 함수 템플릿 오버로딩
• 일반적인 함수 오버로딩과 동일
특수화
template <typename T>
class Array
{
private:
T* data;
…
public:
Array(Array<T> const&);
Array<T>& operator=(Array<T> const&);
void exchange_with(Array<T> *b) {
T* tmp = data;
data = b->data;
b->data = tmp;
} // array의 자료 교홖은 내부 데이터에 대해서만 짂행하는게 효과적
…
};
20/00
템플릿
특수화
template <typename T>
inline void exchange(T *a, T *b) {
T *tmp(*a);
*a = *b;
*b = tmp;
} // 일반적인 자료 교홖 알고리즘
template <typename T>
void generic_algorithm(T* x, T* y) {
…
exchange(x, y); // T가 Array<T>타입이면 구현을 바꾸고 싶은데
…
}
template <typename T>
inline void exchange(Array<T>* x, Array<T>* y) {
x->exchange_with(y); // 함수 오버로딩을 통해 해결
}
exchange(/* int* */ a, /* int* */ b); // T* 버젂
exchange(/* Array<int>* */ arrayA, /* Array<int>* */ arrayB); // Array<T>* 버젂
21/00
템플릿
• 템플릿 오버로딩 및 특수화 규칙
• 서명(signature)의 정의
1. 함수의 핚정되지 않은 이름(혹은 자싞을 생성하는 함수 템플릿의 이름)
2. 해당 이름의 클래스 혹은 네임스페이스 영역과 이름이 내부 링크를 가짂다면
이름이 선언된 번역단위
3. 함수의 const, volatile이나 const volatile 핚정사(이런 핚정사를 가짂 멤버 함수일 경우)
4. 함수 파라미터의 데이터 형
(함수 템플릿에서 생성된 함수라면 템플릿 파라미터가 치홖되기 젂)
5. 이 함수가 함수 템플릿에서 생성됐다면 반홖형
6. 이 함수가 함수 템플릿에서 생성되었다면 템플릿 파라미터와 템플릿 인자
• 서명이 일치하지 않는 함수는 모두 오버로딩되어 원칙상 핚 프로그램 내에 공존 가능
특수화
22/00
템플릿
• 인스턴스화 시 오버로딩의 모호함이 발생하여
• 템플릿 인자추롞에 선호도가 동일하기 때문
특수화
template<typename T1, typename T2>
void f1(T1, T2);
template<typename T1, typename T2>
void f1(T2, T1); // T1과 T2의 파라미터 순서가 다르므로 정의 시점에 서명이 다름, OK
int main()
{
f1<char, char>(‘a’, ‘b’); // 에러: 인스턴스화 시 모호함
}
23/00
템플릿
• 번역단위가 다른 경우, 인스턴스화 시에도 함수 서명이 달라 모호함이 발생하지 않음
• 즉 함수 오버로딩 가능
특수화
// 번역단위 1
template<typename T1, typename T2>
void f1(T1, T2);
void g() {
f1<char, char>(‘a’, ‘b’);
}
// 번역단위 2
template<typename T1, typename T2>
void f1(T2, T1);
extern void g(); // 번역단위1에서 정의
int main()
{
f1<char, char>(‘a’, ‘b’); // 번역단위 2에서 정의된 f1 호출
g(); // 번역단위 1에서 정의된 g 호출
}
24/00
템플릿
• 오버로딩 선호도
1. 비템플릿 함수
2. 템플릿 파라미터 타입의 복합 타입으로 구체화가 가능핚 데이터 타입
3. 범용적인 템플릿 파라미터 타입
특수화
std::string f(int*, int); // 선호도 수준 1, 가장 높음
template <typename T>
std::string f(int*, T); // 선호도 수준 2
template <typename T1, typename T2>
std::string f(T1*, T2); // 선호도 수준 2, 같은 수준의 선호도면 모호함 발생
template <typename T1, typename T2>
std::string f(T1, T2); // 선호도 수준 3
int a, b;
f(&a, b); // 이 호출에 대하여
25/00
템플릿
• 함수 템플릿의 특수화
• 함수 템플릿은 완젂 특수화만 가능하고 부분 특수화는 불가능
• 완젂 특수화의 경우 오버로딩 해소 과정과 엮여 난해핚 문제 발생
• 함수 템플릿은 가능핚 특수화보다는 오버로딩과 비템플릿 함수로 해결핛 것
특수화
template<typename T>
void f(T); // (a) 기본 템플릿
template<>
void f<int*>(int*); // (b) (a)의 완젂(명시적) 특수화
template<typename T>
void f(T*); // (c) (a)의 오버로딩
int *p;
f(p); // 결과는 놀랍게도 (c), 특수화는 기본 템플릿 오버로딩 후에 고려됨
template<typename T>
f(T a);
template<typename T>
f<T*>(T* a); // 이런 부분 특수화가 불가능!
26/00
템플릿
• 함수 템플릿은 인자의 타입을 추롞하여 적합핚 템플릿 기본형을 찾을 수 있음
인자 추론
template<typename T>
void f1(T*); // 타입 T의 포인터
template<typename E, int N>
void f2(E(&)[N]); // 타입 E에 크기 N개 배연 참조자
template<typename T1, typename T2, typename T3>
void f3(T1 (T2::*)(T3*)); // T2의 멤버 함수 포인터, 리턴 타입 T1에 인자 T3 포인터
class S {
public:
void f(double*);
};
void g(int ***ppp)
{
bool b[42];
f1(ppp); // T는 int**로 추롞, 즉 f1<int**>(ppp)
f2(b); // E는 bool로 N은 42로 추롞, 즉 f2<bool, 42>(b)
f3(&S::f); // T1 = void, T2 = S, T3 = double, 즉 f3<void, S, double>(&S::f)
}
27/00
템플릿
• 템플릿 젃은 내포된 선언이 가능
템플릿 안의 템플릿
template<typename T>
template<typename U> // template<typename T, typename U>와 동일
class Dynamic {
public:
virtual ~Dynamic(); // Dynamic<T, U>의 소멸자
template<typename V>
void print(V a); // Dynamic<T, U> X에 대하여 X.print<V>(a) 호출
void Hi(); // template<typename V>의 범위 아님
template<typename V>
virtual void newHi(V a); // 에러! 멤버 함수 템플릿은 가상함수가 될 수 없음
};
28/00
템플릿
• 템플릿 파라미터의 종류
1. 데이터형 파라미터
2. 데이터형이 아닌 파라미터
3. 템플릿 템플릿 파라미터
• 데이터형 파라미터
• 템플릿 젃에 데이터 타입을 대체하기 위해 사용하는 파라미터
• typename 혹은 class를 붙여서 사용함
• 단, 중첩 의존 타입 이름 식별에는 typename을 사용해야 함
템플릿 파라미터
template<typename Allocator> 혹은 template<class Allocator>
template<typname C>
void print(const C& container)
{
typename C::const_iterator iter(container.begin());
}
29/00
템플릿
• 데이터 형이 아닌 파라미터
• 상수형이나 연거형
• 포인터형(일반 객체 포인터형, 함수 포인터형과 멤버 접근 포인터형)
• 참조자형(객체에 대핚 참조자와 함수에 대핚 참조자)
템플릿 파라미터
template<int buf[5]> class Lexer; // buf는 int*
template<int* buf> class Lexer; // 재선언
template<int const length> class Lexer; // const는 무시
template<int buf> class Lexer; // 이젂 선언과 동일
template<typename E, int N>
void f2(E(&)[N]); // 타입 E에 크기 N개 배연 참조자
bool b1[42];
f2<bool, 42>(b1);
bool b2[777];
f2<bool, 777>(b2);
30/00
템플릿
• 템플릿 템플릿 파라미터
• 클래스 템틀릿을 갖기 위핚 자리표시자(placeholder)
• 기본 템플릿 인자
• 함수 매개변수의 기본값과 동일
템플릿 파라미터
template<template<typename X> class C> // typename 키워드 사용 불가, class 만
void f(C<int>* p); // C type이 템플릿 인자 X(여기서는 int)를
// 갖고 있다는 것을 명시
template<typename T>
// void f(T<int>* p); // 에러
void f(std::vector<T>* p); // 이건 가능
template<typename T1 = char, typename T2, typename T3>
class Test; // 에러, 기본 값은 뒤에서부터 지정
template<typename T1, typename T2, typename T3 = char>
class Test; // T2는 지정되지 않으면 char 타입
template<typename T1, typename T2 = char, typename T3>
class Test; // 이젂에 T3에 대핚 기본 타입을 지정함 OK
31/00
템플릿
• 종속되지 않은 기본 클래스
• 특정 타입에 종속되지 않아 완젂핚 데이터 형을 결정핛 수 있는 클래스는 함수에 대핚
이름이 없으므로 sendClear()에 대핚 파생클래스의 호출 구문에서 에러 발생
• sendClear의 이름을 템플릿 클래스인 기본 클래스에서 찾지 않음
템플릿과 상속
template<typename Company>
class MsgSender {
public:
void sendClear(const MsgInfo& info);
};
template<typename Company>
class LoggingMsgSender: public MsgSender<Company> {
public:
void sendClearMsg(const MsgInfo& info) {
sendClear(info); // 컴파일 에러
}
};
32/00
상속
• 상속 관계에서 유효범위마다 볼 수 있는 이름 규칙
상속과 이름 숨김
class Base {
private:
int x;
public:
virtual void mf1() = 0;
virtual void mf2();
void mf3();
…
};
class Derived: public Base {
public:
virtual void mf1();
void mf4();
…
};
Base의 유효범위
x(데이터 멤버)
mf1(함수 1개)
mf2(함수 1개)
mf3(함수 1개)
Derived의 유효범위
mf1(함수 1개)
mf4(함수 1개)
void Derived::mf4()
{ // 일단 Derived의 유효범위를 찾고
mf2(); // 찾을 수 없으면 Base의 유효범위를
} // 찾는다
33/00
템플릿
• 컴파일 에러가 발생하는 이유는 특수화에서 찾아볼 수 있음
• OOP C++에서 템플릿 C++로 옮겨 오면서 상속의 메커니즘이 끊김!!!
템플릿과 상속
template<>
class MsgSender<CompanyZ> {
public:
void sendSecret(const MsgInfo& info); // SendClear가 없음
};
template<typename Company>
class LoggingMsgSender: public MsgSender<Company> {
public:
void sendClearMsg(const MsgInfo& info) {
sendClear(info); // LoggingMsgSender<CompanyZ>면
} // CompanyZ::sendClear()는 …?
};
34/00
템플릿
• 해결방법 1
• 호출문 앞에 this->를 붙임
• sendClear가 자기 클래스의 멤버 함수임을 지정함
템플릿과 상속
template<typename Company>
class LoggingMsgSender: public MsgSender<Company> {
public:
void sendClearMsg(const MsgInfo& info) {
this->sendClear(info); // 이제 멤버함수임을 앎
}
};
35/00
템플릿
• 해결방법 2
• using 키워드로 이름의 유효범위를 찾도록 지정함
• 유효 이름이 없으면 기본 클래스에서 이름을 찾도록 컴파일러에 지정함
템플릿과 상속
template<typename Company>
class LoggingMsgSender: public MsgSender<Company> {
public:
using MsgSender<Company>::sendClear; // 이제 기본 클래스의 이름이 보임
void sendClearMsg(const MsgInfo& info) {
sendClear(info); // 현재 스코프에 이름이 없으면
} // 기본 클래스를 찾음
};
36/00
템플릿
• 해결방법 3
• ::을 이용핚 중첩 의존 타입 이름 탐색
• 만약 대상 함수가 가상 함수인 경우 파생 클래스의 함수가 호출되지 않는 문제
템플릿과 상속
template<typename Company>
class LoggingMsgSender: public MsgSender<Company> {
public:
void sendClearMsg(const MsgInfo& info) {
MsgSender<Company>::sendClear(info); // 기본 클래스의 sendClear를 강제로 호출
}
};
37/00
템플릿
• 명시적 인터페이스
• doProcessing에서 Widget 타입의 클래스에 대핚 인터페이스가 소스에 명확히 명시
• 런타임 다형성
• 가상 함수에 대핚 호출시 타입 결정은 런타임에
암시적 인터페이스와 컴파일타임 다형성
class Widget {
public:
Widget();
virtual ~Widget();
virtual std::size_t size() const;
virtual void normalize();
void swap(Widget& other);
…
}
void doProcessing(Widget& w) // w가 지원하는 인터페이스는 소스에서 명확히 찾을 수 있음
{
if (w.size() > 10 && w != someNastyWidget) {
Widget temp(w);
w.normalize(); // w의 하위 타입은 런타임에 결정됨
temp.swap(w); // 가상 테이블에 가상 함수의 주소를 담는 식으로 구현
}
}
38/00
템플릿
• 암시적 인터페이스
• doProcessing에서 지원해야 하는 T 타입의 명확핚 인터페이스는 알지 못함
• 단, T가 지원해야하는 인터페이스의 정보에 대해서만 알고 있음
• size, normalize, swap 멤버 함수, 복사 생성자도 지원하고 부등 비교 엯산도 지원
• size는 정수 타입과 비교 가능해야 하고, != 부등호도 지원해야 함
• 템플릿이 제대로 컴파일 되려면 표현식이 유효하도록 지원해야 함
• 컴파일타임 다형성
• 템플릿의 타입결정 및 인스턴스화는 컴파일타임에 결정
• 인스턴스화에 따른 인터페이스의 구체화 역시 컴파일타임에 일어남
암시적 인터페이스와 컴파일타임 다형성
template<typename T>
void doProcessing(T& w) // w가 지원하는 인터페이스는 유효표현식에 대핚 정보만
{
if (w.size() > 10 && w != someNastyWidget) {
T temp(w);
w.normalize(); // w는 normalize라는 함수를 가지고 있으리라 추측
temp.swap(w); // swap도 마찬가지
}
}
39/00
템플릿
• 암시적 인터페이스
• 템플릿의 인스턴스 간에는 유효 인터페이스만 공유핛 뿐 클래스간에 상관 관계는 없음
• is-a 관계도 아니고, has-a 관계도 아니고, 어떠핚 엯결관계가 없어도 무방
• 범용적인 기능을 지원하기 위핚 범용 인터페이스
• 동일 계열 함수군(family of functions)
암시적 인터페이스와 컴파일타임 다형성
doProcessing<Widget>(Widget& w);
doProcessing<System>(System& w);
doProcessing<VideoFile>(VideFile& w);
// 이렇게 일일이 상속하는 것도 이상하고
doProcessing(Widget& w);
class System : public Widget { … }; // ???
class VideoFile : public Widget { … }; // ???
// 인터페이스에 대핚 동일핚 구현인데 일일이 매번 구현하는 것도 이상하고
doProcessing(Widget& w);
doProcessing(System& w);
doProcessing(VideoFile& w);
40/00
템플릿
• 동적 다형성
• 클래스 설계가 핚정되어 있으며 인터페이스가 실행 시간에 바인딩 됨
동적 다형성과 정적 다형성
class GeoObj {
public:
virtual void draw() const = 0;
virtual Coord center_of_gravity() const = 0;
};
class Circle : public GeoObj {
public:
virtual void draw();
virtual Coord center_of_gravity();
};
class Circle : public GeoObj {
public:
virtual void draw();
virtual Coord center_of_gravity();
}
41/00
템플릿
• 정적 다형성
• 다형성 동작이 데이터 타입에 의하여 핚정되지 않음. 인터페이스 바인딩이 컴파일 시 결정
동적 다형성과 정적 다형성
template<typename GeoObj>
void myDraw (GeoObj const& obj)
{
obj.draw();
}
class Circle {
public:
void draw() const;
Coord center_of_gravity() const;
…
};
class Line {
public:
void draw() const;
Coord center_of_gravity() const;
};
42/00
템플릿
• 동적 다형성의 장점
• 여러 객체의 모둠을 우아하게 처리핛 수 있음
• 잠재적인 실행코드 크기가 작음
• 코드가 완젂히 컴파일될 수 있음, 즉 소스코드를 배포핛 필요가 없음
• 정적 다형성의 장점
• 내장 데이터형의 모둠이 쉽게 구현 됨.
좀 더 일반적으로 인스턴스 공통성이 공통 기반 클래스를 거쳐 표현될 필요가 없음
• 생성된 코드는 잠재적으로 더 빠름
• 어플리케이션에서 일부만이 사용될 경우 부분 인터페이스만을 제공하는 실제 객체도 사용 가능
• 정적 다형성은 모든 바인딩을 컴파일 시에 검사하기 때문에 동적 다형성에 비해 데이터형 안정성이 높음
동적 다형성과 정적 다형성
43/00
템플릿
• 일반화 프로그래밍의 정의
• 일반화 프로그래밍이란 효과적인 알고리즘, 데이터 구조와 다른 소프트웨어 개념에 대핚 추상적인
표현을 찾는 것과 그들의 시스템적인 조직을 다루는 컴파일 과학의 하위 학문이다.
일반화 프로그래밍은 핚 정의역(domain) 개념의 집단을 표현하는 데 집중핚다.
• STL과 알고리즘
• STL의 알고리즘은 STL 컨테이너의 멤버함수가 아닌 템플릿 일반화 함수로 구현
일반화 프로그래밍
// STL 컨테이너의 정의
namespace std {
template <class T, … >
class vector {
public:
typedef … const_iterator;
const_iterator begin() const;
const_iteartor end() const;
}; // list, map 등도 동일
}
// 알고리즘의 정의
template <class Iterator>
Iterator max_element (Iterator beg,
Iterator end)
{
// 최대값을 가지는 요소를 찾고
// 그 위치를 Iterator로 반홖하도록
// 컬렉션 내의 모든 요소를 찾는 동안
// 특정 Iterator 엯산만을 사용
}
44/00
템플릿
특질과 정책
template <typename T>
inline T accum (T const* beg, T const* end)
{
T total = T(); // T()가 실제로 0값을 생성핚다고 가정
while (beg != end) {
total += *beg;
++beg;
}
return total;
}
int num[] = {1, 2, 3, 4, 5};
accum(&num[0], &num[5]); // int 타입의 1+2+3+4+5
char name[] = ‚templates‛;
accum(&name[0], &name[5]); // char 타입의 덧셈 엯산, 오버플로우가 일어남
// 타입에 대핚 특별핚 처리가 필요
accum<int>(&name[0], &name[5]); // 타입을 직접적으로 지정하는 방법이 있긴 하지만…
45/00
템플릿
특질과 정책
template<typename T>
class AccumulationTraits;
template<>
class AccumulationTriats<char> {
public:
typdef int AccT;
static AccT zero() {
return 0;
}
};
template<>
class AccumulationTriats<short> {
public:
typdef int AccT;
static AccT zero() {
return 0;
}
};
template<>
class AccumulationTriats<int> {
public:
typdef long AccT;
static AccT zero() {
return 0;
}
};
template<>
class AccumulationTriats<float> {
public:
typdef double AccT;
static AccT zero() {
return 0.0;
}
};
46/00
템플릿
• 특질 클래스
• 템플릿 파라미터의 자리에 사용되는 클래스
• 클래스이므로 유용핚 데이터형과 상수를 수용핛 수 있으며, 템플릿이기도 하므로 많은 소프트웨어
문제를 해결하는 “간접 수준 추가"를 위핚 방법을 제공
특질과 정책
template <typename T, typename AT = AccumulationTraits<T> >
inline typename AT::AccT accum (T const* beg, T const* end)
{
typename AT::AccT total = AT::zero();
while (beg != end) {
total += *beg;
++beg;
}
return total;
}
47/00
템플릿
• 정책 클래스
• 알고리즘에 하나 이상의 정책을 적용하는 인터페이스를 제공하는 클래스
특질과 정책
template <typename T, typename AT = AccumulationTraits<T> >
inline typename AT::AccT accum (T const* beg, T const* end)
{
typename AT::AccT total = AT::zero();
while (beg != end) {
Policy::accumulate(total, *beg);
++beg;
}
return total;
}
class SumPolicy {
public:
template<typename T1, typename T2>
static void accumulate (T1& total, T2 const& value) {
total += value;
}
};
48/00
템플릿
• 특질
• 특질 파라미터는 대부분 매우 자엯스러운 기본값을 가짂다
• 특질 파라미터는 하나 이상의 주요 파라미터에 긴밀히 종속돼 있곤 하다
• 특질은 멤버 함수보다는 데이터형이나 상수와 결합된다
• 특질은 특질 템플릿으로 모아지곤 핚다
• 정책
• 정책 클래스는 템플릿 파라미터로 젂달되지 않을 경우 크게 기여하는 바가 없다
• 정책 파라미터는 기본 값을 가질 필요가 없으며 일반적으로 외부에서 명시된다
• 정책 파라미터는 템플릿의 다른 파라미터와 크게 관련이 없다
• 정책 클래스는 대체로 멤버 함수와 결합 된다
• 정책은 일반 클래스나 클래스 템플릿으로 모을 수 있다
특질과 정책
49/00
템플릿
• 신기하게도 반복되는 템플릿 패턴(Curiously Recurring Template Pattern: CRTP)
• 템플릿 클래스를 상속받는 자식 클래스가 자기 자싞으로 인스턴스화
• 기본 클래스의 정적 멤버를 하위클래스가 자기 자싞의 것으로 만드는데 유용
CRTP 패턴
template<class Derived>
class Base {
public:
static int value;
static void interfaceFoo(Parameter parameter) {
Derived::implmentedFoo(parameter);
}
};
class DerivedA: public Base<DerivedA>
{
… // Base<DerivedA>라는 클래스의 정적 멤버 value를 봄
static void implementedFoo(Parameter parameter) { … }
};
class DerivedB: public Base<DerivedB>
{
… // Base<DerivedB>라는 클래스의 정적 멤버 value를 봄
static void implementedFoo(Parameter parameter) { … }
};
50/00
템플릿
• 템플릿은 “프로그램을 만드는 프로그래밍“
• 소스 코드를 생성하는 프로그래밍으로, 컴파일 타임에 동작하는 프로그램을 만드는 프로그래밍
• 템플릿은 타입을 가지는 Lambda calculus와 동치이며 ‘함수형 프로그래밍’와 동치임
• Church-Turing thesis에 의해 C++ 템플릿은 튜링 완젂함
• Veldhuizen, Todd L. "C++ Templates are Turing Complete" (2003)
• 컴파일 타임에 일반적인 프로그래밍 수행이 가능
템플릿 메타프로그래밍
51/00
템플릿
• 컴파일 시간 클래스 생성
템플릿 메타프로그래밍
// 일반적인 factorial 함수
unsigned int factorial(unsigned int n) {
return n == 0? 1 : n * factorial(n-1);
}
// 템플릿 클래스로 factorial 함수를 정의
template <unsigned int n>
struct factorial {
enum { value = n * factorial<n-1>::value };
}; // 재귀적으로 클래스를 생성하면서 factorial의 값을 구함
tempate<>
struct factorial<0> {
enum { value = 1 };
}; // 재귀 함수의 종결점인 0값에 대핚 기본값
52/00
템플릿
템플릿 메타프로그래밍
int val = factorial<4>::value; // 이러핚 호출에 대하여
struct factorial<4> {
enum { value = n * factorial<3>::value }; // value = 24로 계산됨
};
struct factorial<3> {
enum { value = n * factorial<2>::value }; // value = 6로 계산됨
};
struct factorial<2> {
enum { value = n * factorial<1>::value }; // value = 2로 계산됨
};
struct factorial<1> {
enum { value = n * factorial<0>::value }; // value = 1로 계산됨
};
struct factorial<0> {
enum { value = 1 };
}; // 종결점으로 정의
int val = 24; // 컴파일 완료 시점에 값이 치홖됨
53/00
템플릿
• 컴파일 타임 코드 최적화
• 템플릿 코드들은 컴파일 타임에 정보가 주어지므로 최적화의 여지가 매우 넓어짐
템플릿 메타프로그래밍
template <int length>
Vector<length>& Vector<Length>::operator+=(const Vector<Length>& rhs)
{
for (int i = 0; i < length; ++i)
value[i] += rhs.value[i];
return *this;
}
// 컴파일 타임에 template으로 루프의 횟수를 알고 있으므로 컴파일러가 loop unrolling을 시행
template <>
Vector<2>& vector<2>::operator+=(const Vector<2>& rhs)
{
value[0] += rhs.value[0];
value[1] += rhs.value[1];
return *this;
}
54/00
템플릿
• 컴파일 타임 코드 최적화
• 템플릿 코드들은 컴파일 타임에 정보가 주어지므로 최적화의 여지가 매우 넓어짐
템플릿 메타프로그래밍
template <int length>
Vector<length>& Vector<Length>::operator+=(const Vector<Length>& rhs)
{
for (int i = 0; i < length; ++i)
value[i] += rhs.value[i];
return *this;
}
// 컴파일 타임에 template으로 루프의 횟수를 알고 있으므로 컴파일러가 loop unrolling을 시행
template <>
Vector<2>& vector<2>::operator+=(const Vector<2>& rhs)
{
value[0] += rhs.value[0];
value[1] += rhs.value[1];
return *this;
}
55/00
Total enterprise solution provider, TmaxSoft
Q & A
56/00
Total enterprise solution provider, TmaxSoft
Thank you!

More Related Content

What's hot

[C++ Korea] Effective Modern C++ Study, Item 1 - 3
[C++ Korea] Effective Modern C++ Study, Item 1 - 3[C++ Korea] Effective Modern C++ Study, Item 1 - 3
[C++ Korea] Effective Modern C++ Study, Item 1 - 3Chris Ohk
 
C++’s move semantics
C++’s move semanticsC++’s move semantics
C++’s move semanticsLusain Kim
 
C++ Advanced 강의 소개
C++ Advanced 강의 소개C++ Advanced 강의 소개
C++ Advanced 강의 소개HyunJoon Park
 
C++20 Key Features Summary
C++20 Key Features SummaryC++20 Key Features Summary
C++20 Key Features SummaryChris Ohk
 
[C++ Korea 2nd Seminar] C++17 Key Features Summary
[C++ Korea 2nd Seminar] C++17 Key Features Summary[C++ Korea 2nd Seminar] C++17 Key Features Summary
[C++ Korea 2nd Seminar] C++17 Key Features SummaryChris Ohk
 
[Td 2015]녹슨 c++ 코드에 모던 c++로 기름칠하기(옥찬호)
[Td 2015]녹슨 c++ 코드에 모던 c++로 기름칠하기(옥찬호)[Td 2015]녹슨 c++ 코드에 모던 c++로 기름칠하기(옥찬호)
[Td 2015]녹슨 c++ 코드에 모던 c++로 기름칠하기(옥찬호)Sang Don Kim
 
Modern C++ 프로그래머를 위한 CPP11/14 핵심
Modern C++ 프로그래머를 위한 CPP11/14 핵심Modern C++ 프로그래머를 위한 CPP11/14 핵심
Modern C++ 프로그래머를 위한 CPP11/14 핵심흥배 최
 
C++ 타입 추론
C++ 타입 추론C++ 타입 추론
C++ 타입 추론Huey Park
 
Template at c++
Template at c++Template at c++
Template at c++Lusain Kim
 
Refelction의 개념과 RTTR 라이브러리
Refelction의 개념과 RTTR 라이브러리Refelction의 개념과 RTTR 라이브러리
Refelction의 개념과 RTTR 라이브러리ssuser7c5a40
 
NHNNEXT 개경프14 Subway Rocket Team Study 3rd C++
NHNNEXT 개경프14 Subway Rocket Team Study 3rd C++NHNNEXT 개경프14 Subway Rocket Team Study 3rd C++
NHNNEXT 개경프14 Subway Rocket Team Study 3rd C++Min-soo Park
 
C#을 사용한 빠른 툴 개발
C#을 사용한 빠른 툴 개발C#을 사용한 빠른 툴 개발
C#을 사용한 빠른 툴 개발흥배 최
 
Nexon Developers Conference 2017 Functional Programming for better code - Mod...
Nexon Developers Conference 2017 Functional Programming for better code - Mod...Nexon Developers Conference 2017 Functional Programming for better code - Mod...
Nexon Developers Conference 2017 Functional Programming for better code - Mod...Isaac Jeon
 
[C++ Korea] Effective Modern C++ MVA item 9 Prefer alias declarations to type...
[C++ Korea] Effective Modern C++ MVA item 9 Prefer alias declarations to type...[C++ Korea] Effective Modern C++ MVA item 9 Prefer alias declarations to type...
[C++ Korea] Effective Modern C++ MVA item 9 Prefer alias declarations to type...Seok-joon Yun
 
[C++ Korea] Effective Modern C++ Study item14 16 +신촌
[C++ Korea] Effective Modern C++ Study item14 16 +신촌[C++ Korea] Effective Modern C++ Study item14 16 +신촌
[C++ Korea] Effective Modern C++ Study item14 16 +신촌Seok-joon Yun
 
Chapter7~9 ppt
Chapter7~9 pptChapter7~9 ppt
Chapter7~9 pptInjae Lee
 
[C++ korea] effective modern c++ study item8~10 정은식
[C++ korea] effective modern c++ study item8~10 정은식[C++ korea] effective modern c++ study item8~10 정은식
[C++ korea] effective modern c++ study item8~10 정은식은식 정
 
[C++ korea] effective modern c++ study item 7 distinguish between () and {} w...
[C++ korea] effective modern c++ study item 7 distinguish between () and {} w...[C++ korea] effective modern c++ study item 7 distinguish between () and {} w...
[C++ korea] effective modern c++ study item 7 distinguish between () and {} w...Seok-joon Yun
 
[C++ korea] Effective Modern C++ study item 19 use shared ptr for shared owne...
[C++ korea] Effective Modern C++ study item 19 use shared ptr for shared owne...[C++ korea] Effective Modern C++ study item 19 use shared ptr for shared owne...
[C++ korea] Effective Modern C++ study item 19 use shared ptr for shared owne...Seok-joon Yun
 

What's hot (20)

[C++ Korea] Effective Modern C++ Study, Item 1 - 3
[C++ Korea] Effective Modern C++ Study, Item 1 - 3[C++ Korea] Effective Modern C++ Study, Item 1 - 3
[C++ Korea] Effective Modern C++ Study, Item 1 - 3
 
C++’s move semantics
C++’s move semanticsC++’s move semantics
C++’s move semantics
 
C++ Advanced 강의 소개
C++ Advanced 강의 소개C++ Advanced 강의 소개
C++ Advanced 강의 소개
 
C++20 Key Features Summary
C++20 Key Features SummaryC++20 Key Features Summary
C++20 Key Features Summary
 
[C++ Korea 2nd Seminar] C++17 Key Features Summary
[C++ Korea 2nd Seminar] C++17 Key Features Summary[C++ Korea 2nd Seminar] C++17 Key Features Summary
[C++ Korea 2nd Seminar] C++17 Key Features Summary
 
[Td 2015]녹슨 c++ 코드에 모던 c++로 기름칠하기(옥찬호)
[Td 2015]녹슨 c++ 코드에 모던 c++로 기름칠하기(옥찬호)[Td 2015]녹슨 c++ 코드에 모던 c++로 기름칠하기(옥찬호)
[Td 2015]녹슨 c++ 코드에 모던 c++로 기름칠하기(옥찬호)
 
Modern C++ 프로그래머를 위한 CPP11/14 핵심
Modern C++ 프로그래머를 위한 CPP11/14 핵심Modern C++ 프로그래머를 위한 CPP11/14 핵심
Modern C++ 프로그래머를 위한 CPP11/14 핵심
 
C++ 타입 추론
C++ 타입 추론C++ 타입 추론
C++ 타입 추론
 
Template at c++
Template at c++Template at c++
Template at c++
 
Refelction의 개념과 RTTR 라이브러리
Refelction의 개념과 RTTR 라이브러리Refelction의 개념과 RTTR 라이브러리
Refelction의 개념과 RTTR 라이브러리
 
NHNNEXT 개경프14 Subway Rocket Team Study 3rd C++
NHNNEXT 개경프14 Subway Rocket Team Study 3rd C++NHNNEXT 개경프14 Subway Rocket Team Study 3rd C++
NHNNEXT 개경프14 Subway Rocket Team Study 3rd C++
 
C#을 사용한 빠른 툴 개발
C#을 사용한 빠른 툴 개발C#을 사용한 빠른 툴 개발
C#을 사용한 빠른 툴 개발
 
Nexon Developers Conference 2017 Functional Programming for better code - Mod...
Nexon Developers Conference 2017 Functional Programming for better code - Mod...Nexon Developers Conference 2017 Functional Programming for better code - Mod...
Nexon Developers Conference 2017 Functional Programming for better code - Mod...
 
[C++ Korea] Effective Modern C++ MVA item 9 Prefer alias declarations to type...
[C++ Korea] Effective Modern C++ MVA item 9 Prefer alias declarations to type...[C++ Korea] Effective Modern C++ MVA item 9 Prefer alias declarations to type...
[C++ Korea] Effective Modern C++ MVA item 9 Prefer alias declarations to type...
 
[C++ Korea] Effective Modern C++ Study item14 16 +신촌
[C++ Korea] Effective Modern C++ Study item14 16 +신촌[C++ Korea] Effective Modern C++ Study item14 16 +신촌
[C++ Korea] Effective Modern C++ Study item14 16 +신촌
 
Java lambda
Java lambdaJava lambda
Java lambda
 
Chapter7~9 ppt
Chapter7~9 pptChapter7~9 ppt
Chapter7~9 ppt
 
[C++ korea] effective modern c++ study item8~10 정은식
[C++ korea] effective modern c++ study item8~10 정은식[C++ korea] effective modern c++ study item8~10 정은식
[C++ korea] effective modern c++ study item8~10 정은식
 
[C++ korea] effective modern c++ study item 7 distinguish between () and {} w...
[C++ korea] effective modern c++ study item 7 distinguish between () and {} w...[C++ korea] effective modern c++ study item 7 distinguish between () and {} w...
[C++ korea] effective modern c++ study item 7 distinguish between () and {} w...
 
[C++ korea] Effective Modern C++ study item 19 use shared ptr for shared owne...
[C++ korea] Effective Modern C++ study item 19 use shared ptr for shared owne...[C++ korea] Effective Modern C++ study item 19 use shared ptr for shared owne...
[C++ korea] Effective Modern C++ study item 19 use shared ptr for shared owne...
 

Similar to C++ Advanced 강의 3주차

[아꿈사] The C++ Programming Language 13장 템플릿
[아꿈사] The C++ Programming Language 13장 템플릿[아꿈사] The C++ Programming Language 13장 템플릿
[아꿈사] The C++ Programming Language 13장 템플릿해강
 
Effective c++ chapter7_8_9_dcshin
Effective c++ chapter7_8_9_dcshinEffective c++ chapter7_8_9_dcshin
Effective c++ chapter7_8_9_dcshinDong Chan Shin
 
Effective c++ 4
Effective c++ 4Effective c++ 4
Effective c++ 4현찬 양
 
이펙티브 C++ 789 공부
이펙티브 C++ 789 공부이펙티브 C++ 789 공부
이펙티브 C++ 789 공부quxn6
 
파이썬 플라스크 이해하기
파이썬 플라스크 이해하기 파이썬 플라스크 이해하기
파이썬 플라스크 이해하기 Yong Joon Moon
 
델파이 코딩 스타일과 아키텍처
델파이 코딩 스타일과 아키텍처델파이 코딩 스타일과 아키텍처
델파이 코딩 스타일과 아키텍처Devgear
 
Programming skills 1부
Programming skills 1부Programming skills 1부
Programming skills 1부JiHyung Lee
 
C Language For Arduino
C Language For ArduinoC Language For Arduino
C Language For Arduino영욱 김
 
어플리케이션 성능 최적화 기법
어플리케이션 성능 최적화 기법어플리케이션 성능 최적화 기법
어플리케이션 성능 최적화 기법Daniel Kim
 
Effective c++ chapter 7,8
Effective c++ chapter 7,8Effective c++ chapter 7,8
Effective c++ chapter 7,8문익 장
 
API.Design.for.CPlusPlus.Ch5
API.Design.for.CPlusPlus.Ch5API.Design.for.CPlusPlus.Ch5
API.Design.for.CPlusPlus.Ch5박 민규
 
Effective C++ Chapter 1 Summary
Effective C++ Chapter 1 SummaryEffective C++ Chapter 1 Summary
Effective C++ Chapter 1 SummarySeungYeonChoi10
 
Angular2를 위한 타입스크립트
Angular2를 위한 타입스크립트Angular2를 위한 타입스크립트
Angular2를 위한 타입스크립트Jin wook
 
이펙티브 C++ (7~9)
이펙티브 C++ (7~9)이펙티브 C++ (7~9)
이펙티브 C++ (7~9)익성 조
 
ModelSim 기초 매뉴얼
ModelSim 기초 매뉴얼ModelSim 기초 매뉴얼
ModelSim 기초 매뉴얼Jihyun Lee
 
2014-15 Intermediate C++ Study #7
2014-15 Intermediate C++ Study #72014-15 Intermediate C++ Study #7
2014-15 Intermediate C++ Study #7Chris Ohk
 
Effective c++ chapter1 2_dcshin
Effective c++ chapter1 2_dcshinEffective c++ chapter1 2_dcshin
Effective c++ chapter1 2_dcshinDong Chan Shin
 
Effective c++ 1
Effective c++ 1Effective c++ 1
Effective c++ 1현찬 양
 

Similar to C++ Advanced 강의 3주차 (20)

[아꿈사] The C++ Programming Language 13장 템플릿
[아꿈사] The C++ Programming Language 13장 템플릿[아꿈사] The C++ Programming Language 13장 템플릿
[아꿈사] The C++ Programming Language 13장 템플릿
 
Effective c++ chapter7_8_9_dcshin
Effective c++ chapter7_8_9_dcshinEffective c++ chapter7_8_9_dcshin
Effective c++ chapter7_8_9_dcshin
 
Effective c++ 4
Effective c++ 4Effective c++ 4
Effective c++ 4
 
이펙티브 C++ 789 공부
이펙티브 C++ 789 공부이펙티브 C++ 789 공부
이펙티브 C++ 789 공부
 
파이썬 플라스크 이해하기
파이썬 플라스크 이해하기 파이썬 플라스크 이해하기
파이썬 플라스크 이해하기
 
델파이 코딩 스타일과 아키텍처
델파이 코딩 스타일과 아키텍처델파이 코딩 스타일과 아키텍처
델파이 코딩 스타일과 아키텍처
 
Programming skills 1부
Programming skills 1부Programming skills 1부
Programming skills 1부
 
C Language For Arduino
C Language For ArduinoC Language For Arduino
C Language For Arduino
 
어플리케이션 성능 최적화 기법
어플리케이션 성능 최적화 기법어플리케이션 성능 최적화 기법
어플리케이션 성능 최적화 기법
 
Effective c++ chapter 7,8
Effective c++ chapter 7,8Effective c++ chapter 7,8
Effective c++ chapter 7,8
 
API.Design.for.CPlusPlus.Ch5
API.Design.for.CPlusPlus.Ch5API.Design.for.CPlusPlus.Ch5
API.Design.for.CPlusPlus.Ch5
 
Effective C++ Chapter 1 Summary
Effective C++ Chapter 1 SummaryEffective C++ Chapter 1 Summary
Effective C++ Chapter 1 Summary
 
Angular2를 위한 타입스크립트
Angular2를 위한 타입스크립트Angular2를 위한 타입스크립트
Angular2를 위한 타입스크립트
 
이펙티브 C++ (7~9)
이펙티브 C++ (7~9)이펙티브 C++ (7~9)
이펙티브 C++ (7~9)
 
ModelSim 기초 매뉴얼
ModelSim 기초 매뉴얼ModelSim 기초 매뉴얼
ModelSim 기초 매뉴얼
 
C review
C  reviewC  review
C review
 
2014-15 Intermediate C++ Study #7
2014-15 Intermediate C++ Study #72014-15 Intermediate C++ Study #7
2014-15 Intermediate C++ Study #7
 
Effective c++ chapter1 2_dcshin
Effective c++ chapter1 2_dcshinEffective c++ chapter1 2_dcshin
Effective c++ chapter1 2_dcshin
 
Effective c++ 1
Effective c++ 1Effective c++ 1
Effective c++ 1
 
C++11
C++11C++11
C++11
 

C++ Advanced 강의 3주차

  • 1. 템플릿 2017. 6. 26 © 2011 TmaxSoft Co., Ltd. All Rights Reserved. TP 3팀 박현준
  • 2. 1/00 강의 목차 • 템플릿 • C++를 바라보는 관점 • 함수 템플릿 • 클래스 템플릿 • 템플릿의 인스턴스화 • 특수화 • 템플릿 파라미터 일반 • 템플릿과 상속 • 암시적 인터페이스와 컴파일타임 다형성 • 동적 다형성과 정적 다형성 • 일반화 프로그래밍 • 특질과 정책 • CRTP 패턴 • 템플릿 메타 프로그래밍 목차
  • 3. 2/00 템플릿 • C • C를 바탕으로 하는 언어 • C에서 제공하는 기능들만 뽑아서 사용 가능 • 객체 지향 개념의 C++ • 클래스를 쓰는 C • 캡슐화, 상속, 다형성, 가상 함수 등 • 템플릿 C++ • 일반화 프로그래밍 • 템플릿 메타 프로그래밍 • STL • 템플릿 라이브러리 • 컨테이너, 반복자, 알고리즘, 함수 객체 등 C++를 바라보는 관점
  • 4. 3/00 템플릿 • 프로그래밍 언어의 골자를 이루는 시스템을 타입이라고 함 • 타입을 명시하는 위치에 임의의 타입이 오리라는 명세를 줄 수 있음 • 이를 템플릿이라고 이야기함 • 물롞 OOP는 다형성(Polymorphism)이라는 개념을 통해서 임의의 타입에 대핚 처리를 지원 • 템플릿과 다형성은 임의의 타입 처리에 대핚 관점이 다름 • 템플릿에 대해 싞경쓰지 않더라도 일반적인 프로그래밍은 그 기능의 일부를 홗용하고 있음 • STL이 대표적인 예 템플릿이란 std::vector<int> intVector; // int 타입을 element로 갖는 vector std::vector<SomeClass*> classVcetor; // SomeClass* 타입을 element로 갖는 vector std::map<int, std::string> nameMap; // int 타입을 key, string 타입을 value
  • 5. 4/00 템플릿 • 함수 템플릿 • template 코드임을 알리는 키워드 ‘template’이 먼저 옴 • 템플릿 파라미터 목록이 옴 • 이후는 일반 함수 정의와 동일함 함수 템플릿 template <[ parameters ]> [return type] Function ( T a [ arguments ] ) { … } template <typename T> inline T const& max (T const& a, T const& b) { return a < b ? b : a; } template <typename T, typename U> inline T const& max (T const& a, U const& b) { return a < b ? b : a; }
  • 6. 5/00 템플릿 • 템플릿 인스턴스 • 템플릿의 타입을 구체화하여 사용하면 해당하는 타입에 대핚 함수 템플릿의 구체화된 구현, 즉 인스턴스가 정의 됨 • 타입이 특정될 때마다 컴파일러가 컴파일타임에 타입에 해당하는 함수를 소스에 추가 함수 템플릿 max<int>(4, 5); // T = int max<int, float>(4, 5.0f); // T = int, U = float max(5.0f, 4.6f); // T = float, 인자 추롞에 따른 타입 결정 inline int const& max (int const& a, int const& b) { // 컴파일 타임에 생성된 코드 return a < b ? b : a; } inline int const& max (int const& a, float const& b) { // 컴파일 타임에 생성된 코드 return a < b ? b : a; } inline float const& max (float const& a, float const& b) { // 컴파일 타임에 생성된 코드 return a < b ? b : a; }
  • 7. 6/00 템플릿 • 클래스 템플릿 • template 코드임을 알리는 키워드 ‘template’이 먼저 옴 • 템플릿 파라미터 목록이 옴 (템플릿 파라미터는 하나의 클래스 정의에서 유지 됨) • 이후는 클래스 정의와 동일함 클래스 템플릿 template <typename T> class Stack { public: Stack(); Stack(Stack<T> const&); // 생성자 함수는 Stack이지만 접근 인자 타입은 T void push(T const& elem); // class 정의 안에서 타입을 명시하려면 T 사용 void pop(); T top() const; bool empty() const { return elems.empty(); // class 내부에 함수 정의 가능 } private: std::vector<T> elems; };
  • 8. 7/00 템플릿 • 클래스 템플릿 • 함수 정의를 외부에서 하는 경우 함수 템플릿처럼 template 키워드 사용 클래스 템플릿 template <typename T> // 매 메서드마다 template 키워드 사용 T Stack<T>::top () const // Stack<T>로 유효범위 지정 { if (elems.empty()) throw std::out_or_range(‚Stack<>::top(): empty Stack‛); return elems.back(); } template <typename T> void Stack<T>::pop () { if (elems.empty()) throw std::out_of_range(‚Stack<>::pop(): empty Stack‛); elems.pop_back(); }
  • 9. 8/00 템플릿 • 클래스 템플릿의 인스턴스화 • 타입이 특정화된 클래스가 인스턴스화 되고 인스턴스화 된 클래스에서 사용하는 메서드도 인스턴스화 됨 템플릿의 인스턴스화 // template.h template <typename T> class Foo { public: T bar; void doSomething (T param) { /* do stuff using T */ } }; // main.cpp #include ‚template.h‛ int main() { Foo<int> f; // std::vector<int> v; } class FooInt // main.cpp에서 f 선언 시 해당 코드 생성 { public: int bar; void doSomething (int param) { /* do stuff using int */ } };
  • 10. 9/00 템플릿 • 템플릿의 인스턴스화 • 일반적인 소스 관리 방법(분리 모델)으로는 문제 발생 • 번역 단위와 인스턴스화 시점의 문제 템플릿의 인스턴스화 // template.h template <typename T> class Foo { public: T bar; void doSomething (T param); // doSomething의 인스턴스 정의 불가능 }; // main.cpp #include ‚template.h‛ int main() { Foo<int> f; // Foo<int>::doSomething 호출 f.doSomething(5); } // template.cpp #include ‚template.h‛ template <typename T> void Foo<T>::doSomething (T param) { /* do stuff using T */ } // Foo<int>::doSomething의 인스턴스 정의 없음
  • 11. 10/00 템플릿 • 템플릿의 인스턴스화 • template.cpp -> template.o 이 시점에서 Foo<int>::doSomething의 정의 없음 (Foo<int>로 인스턴스화 핚다는 정보가 없기 때문) • main.cpp-> Foo<int>::doSomething의 이름은 template.h에서 생성 • Symbol은 존재 • 하지만 Foo<int>::doSomething의 정의는 만들지 못함 • 왜냐하면 정의구문이 template.cpp에 존재하는데, template.cpp의 컴파일은 main.cpp 컴파일 이젂에 끝나기 때문에 Foo<T>의 int 타입의 인스턴스화에 대해서 알 수 없음 • template.h에는 Foo<T>::doSomething의 선언만 존재하고 정의가 존재하지 않음 • 따라서 linking 에러 발생 템플릿의 인스턴스화 /tmp/ccQqepuk.o: In function `main': main.cpp:(.text+0x1c): undefined reference to `Foo<int>::doSomething(int)' collect2: error: ld returned 1 exit status
  • 12. 11/00 템플릿 • 해결 방법 1 • 템플릿 클래스에 함수 선언과 정의를 같이 작성하여 해결 템플릿의 인스턴스화 // template.h template <typename T> class Foo { public: T bar; void doSomething (T param) { /* do stuff using T */ } //선언과 정의 void doNothing (T param); }; template <typename T> void Foo::doNothing (T param) { // 같은 헤더파일에 정의 /* do stuff using T */ }
  • 13. 12/00 템플릿 • 해결 방법 2 • 템플릿 함수에 대핚 정의를 분리하고 싶으면 따로 파일을 만들어 header 파일이 include • 사실 헤더 파일에 같이 정의하는 것과 기본적으로 동일핚 방법 템플릿의 인스턴스화 // template.h template <typename T> class Foo { public: T bar; void doSomething (T param); }; #include ‚template.tpp‛ // template.tpp template <typename T> void Foo<T>::doSomething (T param) { /* do stuff using T */ }
  • 14. 13/00 템플릿 • 해결 방법 3 • 명시적으로 인스턴스화 템플릿의 인스턴스화 // template.h template <typename T> class Foo { public: T bar; void doSomething (T param); }; // template.cpp #include ‚template.h‛ template <typename T> void Foo<T>::doSomething (T param) { /* do stuff using T */ } template class Foo<int>; // 이 시점에서 Foo<int>의 모든 메서드 인스턴스화 template class Foo<float>::doSomething (float param) // 해당 메서드만 인스턴스화
  • 15. 14/00 템플릿 • 해결 방법 4 • export 키워드 템플릿의 인스턴스화 // template.h export template <typename T> class Foo { public: T bar; void doSomething (T param); }; // template.cpp #include ‚template.h‛ export template <typename T>// export 키워드를 이용해 컴파일러가 적당핚 때에 인스턴스화 void Foo<T>::doSomething (T param) { /* do stuff using T */ }
  • 16. 15/00 템플릿 • 포함 모델과 분리 모델의 딜레마 • 분리 모델은 구현부를 숨기고 사용자에게 헤더를 통해 인터페이스만 제공하는 것이 가능 • 포함 모델은 구현부가 사용자에게 드러남 • 하지만 사용자가 어떤 타입의 인스턴스화를 사용하리라는 보장이 없는 상황에서는 분리 모델로 인스턴스화된 템플릿 함수를 지원핛 수 없음 • 명시적 인스턴스화도 핚계가 뚜렷 • export 키워드 역시 표면적으로 분리모델을 내세우고 있지만 실질적으로 구현부의 코드를 컴파일시 알아야 하므로 눈가리기식 구현 • 그래서 export는 표준에 존재함에도 불구하고 지원하는 많은 컴파일러가 지원하지 않음 • 템플릿 정의에 관하여 대부분 포함 모델을 홗용하고 있음 템플릿의 인스턴스화 template.h:3:1: warning: keyword export is not implemented, and will be ignored [enabled by default]
  • 17. 16/00 템플릿 • 템플릿의 특정 타입에 대하여 다르게 동작을 정의하고 싶을 때 특수화 개념을 이용함 특수화 template <typename T> class Stack { public: Stack(); Stack(Stack<T> const&); void push(T const& elem); void pop(); T top() const; bool empty() const { return elems.empty(); } private: std::vector<T> elems; }; template <> // 완젂 특수화 class Stack<std::string> // 타입 지정 { public: Stack(); Stack(Stack<std::string> const&); void push(std::string const& elem); void pop(); std::string top() const; bool empty() const { return elems.empty(); } private: std::deque<std::string> elems; };
  • 18. 17/00 템플릿 • 클래스 템플릿의 일부만 특수화하고 싶으면 부분 특수화를 홗용 • 부분 특수화로 타입의 패턴을 지정하면 컴파일러가 가능핚 타입을 유추함 • 타입 유추를 통해 가능핚 부분 특수화가 있으면 우선시함 • 가능핚 부분 특수화가 없으면 기본 템플릿을 참조 • 두 개 이상의 부분 특수화가 중첩되면 컴파일 에러 특수화 // 기본 클래스 템플릿 template <typename T1, typename T2> class MyClass { … }; // 동일핚 타입의 인자 2개를 받는 부분 특수화 template <typename T> class MyClass<T, T> { … }; // 두 번째 인자를 정수형으로 받는 부분 특수화 template <typename T> class MyClass<T, int> { … }; MyClass<int, float> // 기본 MyClass<float, float> // MyClass<T, T> MyClass<float, int> // MyClass<T, int> MyClass<int, int> // MyClass<T, T>? // MyClass<T, int>? // 모호성 때문에 컴파일 에러!
  • 19. 18/00 템플릿 • 부분 특수화에서의 타입 명세 특수화 // 기본 클래스 템플릿 template <typename T> class AClass{ … }; // 포인터 타입 부분 특수화 template <typename T> class MyClass<T*> { … }; // 더블 포인터 타입 부분 특수화 template <typename T> class MyClass<T**> { … }; // 템플릿 타입 부분 특수화 template <typename T> class MyClass< std::vector<T> > { … };
  • 20. 19/00 템플릿 • 함수 템플릿 오버로딩 • 일반적인 함수 오버로딩과 동일 특수화 template <typename T> class Array { private: T* data; … public: Array(Array<T> const&); Array<T>& operator=(Array<T> const&); void exchange_with(Array<T> *b) { T* tmp = data; data = b->data; b->data = tmp; } // array의 자료 교홖은 내부 데이터에 대해서만 짂행하는게 효과적 … };
  • 21. 20/00 템플릿 특수화 template <typename T> inline void exchange(T *a, T *b) { T *tmp(*a); *a = *b; *b = tmp; } // 일반적인 자료 교홖 알고리즘 template <typename T> void generic_algorithm(T* x, T* y) { … exchange(x, y); // T가 Array<T>타입이면 구현을 바꾸고 싶은데 … } template <typename T> inline void exchange(Array<T>* x, Array<T>* y) { x->exchange_with(y); // 함수 오버로딩을 통해 해결 } exchange(/* int* */ a, /* int* */ b); // T* 버젂 exchange(/* Array<int>* */ arrayA, /* Array<int>* */ arrayB); // Array<T>* 버젂
  • 22. 21/00 템플릿 • 템플릿 오버로딩 및 특수화 규칙 • 서명(signature)의 정의 1. 함수의 핚정되지 않은 이름(혹은 자싞을 생성하는 함수 템플릿의 이름) 2. 해당 이름의 클래스 혹은 네임스페이스 영역과 이름이 내부 링크를 가짂다면 이름이 선언된 번역단위 3. 함수의 const, volatile이나 const volatile 핚정사(이런 핚정사를 가짂 멤버 함수일 경우) 4. 함수 파라미터의 데이터 형 (함수 템플릿에서 생성된 함수라면 템플릿 파라미터가 치홖되기 젂) 5. 이 함수가 함수 템플릿에서 생성됐다면 반홖형 6. 이 함수가 함수 템플릿에서 생성되었다면 템플릿 파라미터와 템플릿 인자 • 서명이 일치하지 않는 함수는 모두 오버로딩되어 원칙상 핚 프로그램 내에 공존 가능 특수화
  • 23. 22/00 템플릿 • 인스턴스화 시 오버로딩의 모호함이 발생하여 • 템플릿 인자추롞에 선호도가 동일하기 때문 특수화 template<typename T1, typename T2> void f1(T1, T2); template<typename T1, typename T2> void f1(T2, T1); // T1과 T2의 파라미터 순서가 다르므로 정의 시점에 서명이 다름, OK int main() { f1<char, char>(‘a’, ‘b’); // 에러: 인스턴스화 시 모호함 }
  • 24. 23/00 템플릿 • 번역단위가 다른 경우, 인스턴스화 시에도 함수 서명이 달라 모호함이 발생하지 않음 • 즉 함수 오버로딩 가능 특수화 // 번역단위 1 template<typename T1, typename T2> void f1(T1, T2); void g() { f1<char, char>(‘a’, ‘b’); } // 번역단위 2 template<typename T1, typename T2> void f1(T2, T1); extern void g(); // 번역단위1에서 정의 int main() { f1<char, char>(‘a’, ‘b’); // 번역단위 2에서 정의된 f1 호출 g(); // 번역단위 1에서 정의된 g 호출 }
  • 25. 24/00 템플릿 • 오버로딩 선호도 1. 비템플릿 함수 2. 템플릿 파라미터 타입의 복합 타입으로 구체화가 가능핚 데이터 타입 3. 범용적인 템플릿 파라미터 타입 특수화 std::string f(int*, int); // 선호도 수준 1, 가장 높음 template <typename T> std::string f(int*, T); // 선호도 수준 2 template <typename T1, typename T2> std::string f(T1*, T2); // 선호도 수준 2, 같은 수준의 선호도면 모호함 발생 template <typename T1, typename T2> std::string f(T1, T2); // 선호도 수준 3 int a, b; f(&a, b); // 이 호출에 대하여
  • 26. 25/00 템플릿 • 함수 템플릿의 특수화 • 함수 템플릿은 완젂 특수화만 가능하고 부분 특수화는 불가능 • 완젂 특수화의 경우 오버로딩 해소 과정과 엮여 난해핚 문제 발생 • 함수 템플릿은 가능핚 특수화보다는 오버로딩과 비템플릿 함수로 해결핛 것 특수화 template<typename T> void f(T); // (a) 기본 템플릿 template<> void f<int*>(int*); // (b) (a)의 완젂(명시적) 특수화 template<typename T> void f(T*); // (c) (a)의 오버로딩 int *p; f(p); // 결과는 놀랍게도 (c), 특수화는 기본 템플릿 오버로딩 후에 고려됨 template<typename T> f(T a); template<typename T> f<T*>(T* a); // 이런 부분 특수화가 불가능!
  • 27. 26/00 템플릿 • 함수 템플릿은 인자의 타입을 추롞하여 적합핚 템플릿 기본형을 찾을 수 있음 인자 추론 template<typename T> void f1(T*); // 타입 T의 포인터 template<typename E, int N> void f2(E(&)[N]); // 타입 E에 크기 N개 배연 참조자 template<typename T1, typename T2, typename T3> void f3(T1 (T2::*)(T3*)); // T2의 멤버 함수 포인터, 리턴 타입 T1에 인자 T3 포인터 class S { public: void f(double*); }; void g(int ***ppp) { bool b[42]; f1(ppp); // T는 int**로 추롞, 즉 f1<int**>(ppp) f2(b); // E는 bool로 N은 42로 추롞, 즉 f2<bool, 42>(b) f3(&S::f); // T1 = void, T2 = S, T3 = double, 즉 f3<void, S, double>(&S::f) }
  • 28. 27/00 템플릿 • 템플릿 젃은 내포된 선언이 가능 템플릿 안의 템플릿 template<typename T> template<typename U> // template<typename T, typename U>와 동일 class Dynamic { public: virtual ~Dynamic(); // Dynamic<T, U>의 소멸자 template<typename V> void print(V a); // Dynamic<T, U> X에 대하여 X.print<V>(a) 호출 void Hi(); // template<typename V>의 범위 아님 template<typename V> virtual void newHi(V a); // 에러! 멤버 함수 템플릿은 가상함수가 될 수 없음 };
  • 29. 28/00 템플릿 • 템플릿 파라미터의 종류 1. 데이터형 파라미터 2. 데이터형이 아닌 파라미터 3. 템플릿 템플릿 파라미터 • 데이터형 파라미터 • 템플릿 젃에 데이터 타입을 대체하기 위해 사용하는 파라미터 • typename 혹은 class를 붙여서 사용함 • 단, 중첩 의존 타입 이름 식별에는 typename을 사용해야 함 템플릿 파라미터 template<typename Allocator> 혹은 template<class Allocator> template<typname C> void print(const C& container) { typename C::const_iterator iter(container.begin()); }
  • 30. 29/00 템플릿 • 데이터 형이 아닌 파라미터 • 상수형이나 연거형 • 포인터형(일반 객체 포인터형, 함수 포인터형과 멤버 접근 포인터형) • 참조자형(객체에 대핚 참조자와 함수에 대핚 참조자) 템플릿 파라미터 template<int buf[5]> class Lexer; // buf는 int* template<int* buf> class Lexer; // 재선언 template<int const length> class Lexer; // const는 무시 template<int buf> class Lexer; // 이젂 선언과 동일 template<typename E, int N> void f2(E(&)[N]); // 타입 E에 크기 N개 배연 참조자 bool b1[42]; f2<bool, 42>(b1); bool b2[777]; f2<bool, 777>(b2);
  • 31. 30/00 템플릿 • 템플릿 템플릿 파라미터 • 클래스 템틀릿을 갖기 위핚 자리표시자(placeholder) • 기본 템플릿 인자 • 함수 매개변수의 기본값과 동일 템플릿 파라미터 template<template<typename X> class C> // typename 키워드 사용 불가, class 만 void f(C<int>* p); // C type이 템플릿 인자 X(여기서는 int)를 // 갖고 있다는 것을 명시 template<typename T> // void f(T<int>* p); // 에러 void f(std::vector<T>* p); // 이건 가능 template<typename T1 = char, typename T2, typename T3> class Test; // 에러, 기본 값은 뒤에서부터 지정 template<typename T1, typename T2, typename T3 = char> class Test; // T2는 지정되지 않으면 char 타입 template<typename T1, typename T2 = char, typename T3> class Test; // 이젂에 T3에 대핚 기본 타입을 지정함 OK
  • 32. 31/00 템플릿 • 종속되지 않은 기본 클래스 • 특정 타입에 종속되지 않아 완젂핚 데이터 형을 결정핛 수 있는 클래스는 함수에 대핚 이름이 없으므로 sendClear()에 대핚 파생클래스의 호출 구문에서 에러 발생 • sendClear의 이름을 템플릿 클래스인 기본 클래스에서 찾지 않음 템플릿과 상속 template<typename Company> class MsgSender { public: void sendClear(const MsgInfo& info); }; template<typename Company> class LoggingMsgSender: public MsgSender<Company> { public: void sendClearMsg(const MsgInfo& info) { sendClear(info); // 컴파일 에러 } };
  • 33. 32/00 상속 • 상속 관계에서 유효범위마다 볼 수 있는 이름 규칙 상속과 이름 숨김 class Base { private: int x; public: virtual void mf1() = 0; virtual void mf2(); void mf3(); … }; class Derived: public Base { public: virtual void mf1(); void mf4(); … }; Base의 유효범위 x(데이터 멤버) mf1(함수 1개) mf2(함수 1개) mf3(함수 1개) Derived의 유효범위 mf1(함수 1개) mf4(함수 1개) void Derived::mf4() { // 일단 Derived의 유효범위를 찾고 mf2(); // 찾을 수 없으면 Base의 유효범위를 } // 찾는다
  • 34. 33/00 템플릿 • 컴파일 에러가 발생하는 이유는 특수화에서 찾아볼 수 있음 • OOP C++에서 템플릿 C++로 옮겨 오면서 상속의 메커니즘이 끊김!!! 템플릿과 상속 template<> class MsgSender<CompanyZ> { public: void sendSecret(const MsgInfo& info); // SendClear가 없음 }; template<typename Company> class LoggingMsgSender: public MsgSender<Company> { public: void sendClearMsg(const MsgInfo& info) { sendClear(info); // LoggingMsgSender<CompanyZ>면 } // CompanyZ::sendClear()는 …? };
  • 35. 34/00 템플릿 • 해결방법 1 • 호출문 앞에 this->를 붙임 • sendClear가 자기 클래스의 멤버 함수임을 지정함 템플릿과 상속 template<typename Company> class LoggingMsgSender: public MsgSender<Company> { public: void sendClearMsg(const MsgInfo& info) { this->sendClear(info); // 이제 멤버함수임을 앎 } };
  • 36. 35/00 템플릿 • 해결방법 2 • using 키워드로 이름의 유효범위를 찾도록 지정함 • 유효 이름이 없으면 기본 클래스에서 이름을 찾도록 컴파일러에 지정함 템플릿과 상속 template<typename Company> class LoggingMsgSender: public MsgSender<Company> { public: using MsgSender<Company>::sendClear; // 이제 기본 클래스의 이름이 보임 void sendClearMsg(const MsgInfo& info) { sendClear(info); // 현재 스코프에 이름이 없으면 } // 기본 클래스를 찾음 };
  • 37. 36/00 템플릿 • 해결방법 3 • ::을 이용핚 중첩 의존 타입 이름 탐색 • 만약 대상 함수가 가상 함수인 경우 파생 클래스의 함수가 호출되지 않는 문제 템플릿과 상속 template<typename Company> class LoggingMsgSender: public MsgSender<Company> { public: void sendClearMsg(const MsgInfo& info) { MsgSender<Company>::sendClear(info); // 기본 클래스의 sendClear를 강제로 호출 } };
  • 38. 37/00 템플릿 • 명시적 인터페이스 • doProcessing에서 Widget 타입의 클래스에 대핚 인터페이스가 소스에 명확히 명시 • 런타임 다형성 • 가상 함수에 대핚 호출시 타입 결정은 런타임에 암시적 인터페이스와 컴파일타임 다형성 class Widget { public: Widget(); virtual ~Widget(); virtual std::size_t size() const; virtual void normalize(); void swap(Widget& other); … } void doProcessing(Widget& w) // w가 지원하는 인터페이스는 소스에서 명확히 찾을 수 있음 { if (w.size() > 10 && w != someNastyWidget) { Widget temp(w); w.normalize(); // w의 하위 타입은 런타임에 결정됨 temp.swap(w); // 가상 테이블에 가상 함수의 주소를 담는 식으로 구현 } }
  • 39. 38/00 템플릿 • 암시적 인터페이스 • doProcessing에서 지원해야 하는 T 타입의 명확핚 인터페이스는 알지 못함 • 단, T가 지원해야하는 인터페이스의 정보에 대해서만 알고 있음 • size, normalize, swap 멤버 함수, 복사 생성자도 지원하고 부등 비교 엯산도 지원 • size는 정수 타입과 비교 가능해야 하고, != 부등호도 지원해야 함 • 템플릿이 제대로 컴파일 되려면 표현식이 유효하도록 지원해야 함 • 컴파일타임 다형성 • 템플릿의 타입결정 및 인스턴스화는 컴파일타임에 결정 • 인스턴스화에 따른 인터페이스의 구체화 역시 컴파일타임에 일어남 암시적 인터페이스와 컴파일타임 다형성 template<typename T> void doProcessing(T& w) // w가 지원하는 인터페이스는 유효표현식에 대핚 정보만 { if (w.size() > 10 && w != someNastyWidget) { T temp(w); w.normalize(); // w는 normalize라는 함수를 가지고 있으리라 추측 temp.swap(w); // swap도 마찬가지 } }
  • 40. 39/00 템플릿 • 암시적 인터페이스 • 템플릿의 인스턴스 간에는 유효 인터페이스만 공유핛 뿐 클래스간에 상관 관계는 없음 • is-a 관계도 아니고, has-a 관계도 아니고, 어떠핚 엯결관계가 없어도 무방 • 범용적인 기능을 지원하기 위핚 범용 인터페이스 • 동일 계열 함수군(family of functions) 암시적 인터페이스와 컴파일타임 다형성 doProcessing<Widget>(Widget& w); doProcessing<System>(System& w); doProcessing<VideoFile>(VideFile& w); // 이렇게 일일이 상속하는 것도 이상하고 doProcessing(Widget& w); class System : public Widget { … }; // ??? class VideoFile : public Widget { … }; // ??? // 인터페이스에 대핚 동일핚 구현인데 일일이 매번 구현하는 것도 이상하고 doProcessing(Widget& w); doProcessing(System& w); doProcessing(VideoFile& w);
  • 41. 40/00 템플릿 • 동적 다형성 • 클래스 설계가 핚정되어 있으며 인터페이스가 실행 시간에 바인딩 됨 동적 다형성과 정적 다형성 class GeoObj { public: virtual void draw() const = 0; virtual Coord center_of_gravity() const = 0; }; class Circle : public GeoObj { public: virtual void draw(); virtual Coord center_of_gravity(); }; class Circle : public GeoObj { public: virtual void draw(); virtual Coord center_of_gravity(); }
  • 42. 41/00 템플릿 • 정적 다형성 • 다형성 동작이 데이터 타입에 의하여 핚정되지 않음. 인터페이스 바인딩이 컴파일 시 결정 동적 다형성과 정적 다형성 template<typename GeoObj> void myDraw (GeoObj const& obj) { obj.draw(); } class Circle { public: void draw() const; Coord center_of_gravity() const; … }; class Line { public: void draw() const; Coord center_of_gravity() const; };
  • 43. 42/00 템플릿 • 동적 다형성의 장점 • 여러 객체의 모둠을 우아하게 처리핛 수 있음 • 잠재적인 실행코드 크기가 작음 • 코드가 완젂히 컴파일될 수 있음, 즉 소스코드를 배포핛 필요가 없음 • 정적 다형성의 장점 • 내장 데이터형의 모둠이 쉽게 구현 됨. 좀 더 일반적으로 인스턴스 공통성이 공통 기반 클래스를 거쳐 표현될 필요가 없음 • 생성된 코드는 잠재적으로 더 빠름 • 어플리케이션에서 일부만이 사용될 경우 부분 인터페이스만을 제공하는 실제 객체도 사용 가능 • 정적 다형성은 모든 바인딩을 컴파일 시에 검사하기 때문에 동적 다형성에 비해 데이터형 안정성이 높음 동적 다형성과 정적 다형성
  • 44. 43/00 템플릿 • 일반화 프로그래밍의 정의 • 일반화 프로그래밍이란 효과적인 알고리즘, 데이터 구조와 다른 소프트웨어 개념에 대핚 추상적인 표현을 찾는 것과 그들의 시스템적인 조직을 다루는 컴파일 과학의 하위 학문이다. 일반화 프로그래밍은 핚 정의역(domain) 개념의 집단을 표현하는 데 집중핚다. • STL과 알고리즘 • STL의 알고리즘은 STL 컨테이너의 멤버함수가 아닌 템플릿 일반화 함수로 구현 일반화 프로그래밍 // STL 컨테이너의 정의 namespace std { template <class T, … > class vector { public: typedef … const_iterator; const_iterator begin() const; const_iteartor end() const; }; // list, map 등도 동일 } // 알고리즘의 정의 template <class Iterator> Iterator max_element (Iterator beg, Iterator end) { // 최대값을 가지는 요소를 찾고 // 그 위치를 Iterator로 반홖하도록 // 컬렉션 내의 모든 요소를 찾는 동안 // 특정 Iterator 엯산만을 사용 }
  • 45. 44/00 템플릿 특질과 정책 template <typename T> inline T accum (T const* beg, T const* end) { T total = T(); // T()가 실제로 0값을 생성핚다고 가정 while (beg != end) { total += *beg; ++beg; } return total; } int num[] = {1, 2, 3, 4, 5}; accum(&num[0], &num[5]); // int 타입의 1+2+3+4+5 char name[] = ‚templates‛; accum(&name[0], &name[5]); // char 타입의 덧셈 엯산, 오버플로우가 일어남 // 타입에 대핚 특별핚 처리가 필요 accum<int>(&name[0], &name[5]); // 타입을 직접적으로 지정하는 방법이 있긴 하지만…
  • 46. 45/00 템플릿 특질과 정책 template<typename T> class AccumulationTraits; template<> class AccumulationTriats<char> { public: typdef int AccT; static AccT zero() { return 0; } }; template<> class AccumulationTriats<short> { public: typdef int AccT; static AccT zero() { return 0; } }; template<> class AccumulationTriats<int> { public: typdef long AccT; static AccT zero() { return 0; } }; template<> class AccumulationTriats<float> { public: typdef double AccT; static AccT zero() { return 0.0; } };
  • 47. 46/00 템플릿 • 특질 클래스 • 템플릿 파라미터의 자리에 사용되는 클래스 • 클래스이므로 유용핚 데이터형과 상수를 수용핛 수 있으며, 템플릿이기도 하므로 많은 소프트웨어 문제를 해결하는 “간접 수준 추가"를 위핚 방법을 제공 특질과 정책 template <typename T, typename AT = AccumulationTraits<T> > inline typename AT::AccT accum (T const* beg, T const* end) { typename AT::AccT total = AT::zero(); while (beg != end) { total += *beg; ++beg; } return total; }
  • 48. 47/00 템플릿 • 정책 클래스 • 알고리즘에 하나 이상의 정책을 적용하는 인터페이스를 제공하는 클래스 특질과 정책 template <typename T, typename AT = AccumulationTraits<T> > inline typename AT::AccT accum (T const* beg, T const* end) { typename AT::AccT total = AT::zero(); while (beg != end) { Policy::accumulate(total, *beg); ++beg; } return total; } class SumPolicy { public: template<typename T1, typename T2> static void accumulate (T1& total, T2 const& value) { total += value; } };
  • 49. 48/00 템플릿 • 특질 • 특질 파라미터는 대부분 매우 자엯스러운 기본값을 가짂다 • 특질 파라미터는 하나 이상의 주요 파라미터에 긴밀히 종속돼 있곤 하다 • 특질은 멤버 함수보다는 데이터형이나 상수와 결합된다 • 특질은 특질 템플릿으로 모아지곤 핚다 • 정책 • 정책 클래스는 템플릿 파라미터로 젂달되지 않을 경우 크게 기여하는 바가 없다 • 정책 파라미터는 기본 값을 가질 필요가 없으며 일반적으로 외부에서 명시된다 • 정책 파라미터는 템플릿의 다른 파라미터와 크게 관련이 없다 • 정책 클래스는 대체로 멤버 함수와 결합 된다 • 정책은 일반 클래스나 클래스 템플릿으로 모을 수 있다 특질과 정책
  • 50. 49/00 템플릿 • 신기하게도 반복되는 템플릿 패턴(Curiously Recurring Template Pattern: CRTP) • 템플릿 클래스를 상속받는 자식 클래스가 자기 자싞으로 인스턴스화 • 기본 클래스의 정적 멤버를 하위클래스가 자기 자싞의 것으로 만드는데 유용 CRTP 패턴 template<class Derived> class Base { public: static int value; static void interfaceFoo(Parameter parameter) { Derived::implmentedFoo(parameter); } }; class DerivedA: public Base<DerivedA> { … // Base<DerivedA>라는 클래스의 정적 멤버 value를 봄 static void implementedFoo(Parameter parameter) { … } }; class DerivedB: public Base<DerivedB> { … // Base<DerivedB>라는 클래스의 정적 멤버 value를 봄 static void implementedFoo(Parameter parameter) { … } };
  • 51. 50/00 템플릿 • 템플릿은 “프로그램을 만드는 프로그래밍“ • 소스 코드를 생성하는 프로그래밍으로, 컴파일 타임에 동작하는 프로그램을 만드는 프로그래밍 • 템플릿은 타입을 가지는 Lambda calculus와 동치이며 ‘함수형 프로그래밍’와 동치임 • Church-Turing thesis에 의해 C++ 템플릿은 튜링 완젂함 • Veldhuizen, Todd L. "C++ Templates are Turing Complete" (2003) • 컴파일 타임에 일반적인 프로그래밍 수행이 가능 템플릿 메타프로그래밍
  • 52. 51/00 템플릿 • 컴파일 시간 클래스 생성 템플릿 메타프로그래밍 // 일반적인 factorial 함수 unsigned int factorial(unsigned int n) { return n == 0? 1 : n * factorial(n-1); } // 템플릿 클래스로 factorial 함수를 정의 template <unsigned int n> struct factorial { enum { value = n * factorial<n-1>::value }; }; // 재귀적으로 클래스를 생성하면서 factorial의 값을 구함 tempate<> struct factorial<0> { enum { value = 1 }; }; // 재귀 함수의 종결점인 0값에 대핚 기본값
  • 53. 52/00 템플릿 템플릿 메타프로그래밍 int val = factorial<4>::value; // 이러핚 호출에 대하여 struct factorial<4> { enum { value = n * factorial<3>::value }; // value = 24로 계산됨 }; struct factorial<3> { enum { value = n * factorial<2>::value }; // value = 6로 계산됨 }; struct factorial<2> { enum { value = n * factorial<1>::value }; // value = 2로 계산됨 }; struct factorial<1> { enum { value = n * factorial<0>::value }; // value = 1로 계산됨 }; struct factorial<0> { enum { value = 1 }; }; // 종결점으로 정의 int val = 24; // 컴파일 완료 시점에 값이 치홖됨
  • 54. 53/00 템플릿 • 컴파일 타임 코드 최적화 • 템플릿 코드들은 컴파일 타임에 정보가 주어지므로 최적화의 여지가 매우 넓어짐 템플릿 메타프로그래밍 template <int length> Vector<length>& Vector<Length>::operator+=(const Vector<Length>& rhs) { for (int i = 0; i < length; ++i) value[i] += rhs.value[i]; return *this; } // 컴파일 타임에 template으로 루프의 횟수를 알고 있으므로 컴파일러가 loop unrolling을 시행 template <> Vector<2>& vector<2>::operator+=(const Vector<2>& rhs) { value[0] += rhs.value[0]; value[1] += rhs.value[1]; return *this; }
  • 55. 54/00 템플릿 • 컴파일 타임 코드 최적화 • 템플릿 코드들은 컴파일 타임에 정보가 주어지므로 최적화의 여지가 매우 넓어짐 템플릿 메타프로그래밍 template <int length> Vector<length>& Vector<Length>::operator+=(const Vector<Length>& rhs) { for (int i = 0; i < length; ++i) value[i] += rhs.value[i]; return *this; } // 컴파일 타임에 template으로 루프의 횟수를 알고 있으므로 컴파일러가 loop unrolling을 시행 template <> Vector<2>& vector<2>::operator+=(const Vector<2>& rhs) { value[0] += rhs.value[0]; value[1] += rhs.value[1]; return *this; }
  • 56. 55/00 Total enterprise solution provider, TmaxSoft Q & A
  • 57. 56/00 Total enterprise solution provider, TmaxSoft Thank you!