'Programming Languages/C++ Templates'에 해당되는 글 4건

  1. 2010.08.31 Advantages of Templates [C++]
  2. 2010.05.10 Template Specifications
  3. 2010.05.10 Templates Overview
  4. 2010.05.09 Templates

[C++] 템플릿의 이점

 

 템플릿은 다음의 경우 사용한다:

  • 어떤 자료형이든 연산이 가능한 typesafe collection class를 만들 때(ex: stack)
  • void형 포인터를 가질 수 있는 함수의 형 검사를 추가할 때
  • 스마트 포인터와 같이 타입에 따른 동작을 수정하는 연산자 중복 그룹 캡슐화를 할 때

 

 대부분의 이런 사용은 템플릿 없이 효력을 발휘할 수 있기는 하다; 그러나, 템플릿은 몇 가지 장점을 제공한다.

  • 템플릿은 작성하기 쉽다. 일일이 특성을 생성하는 대신 클래스나 함수의 일반적인 버전 하나만 만들면 된다.
  • 템플릿은 더 이해하기 쉬워지므로, 추상 타입 정보의 방식을 올바로 제공할 수 있다.
  • 템플릿은 typesafe하다. 왜냐하면 템플릿의 동작에 따른 타입이 컴파일 타임에 결정되어 컴파일러가 에러 발생 전에 타입을 검사하여 반응할 수 있기 때문이다.

 

더 많은 정보를 위해서 아래의 내용들을 보자. 

  • Templates and Macros
  • Templates and Void Pointers
  • Templates and Smart Pointers
  • Templates and Collection Classes


Templates and Macros
(템플릿과 매크로)


다수의 경우, 템플릿은 자료형을 결정짓는 템플릿화 변수(templated variable)를 대체하는 매크로 전처리기(preprocessor macros)처럼 동작한다. 하지만 매크로와:

define min(i, j) (((i) < (j)) ? (i) : (j))

템플릿:

template<class T> T min (T i, T j) { return ((i < j) ? i : j) }

에는 많은 차이가 있다.

 
매크로에는 다음과 같은 문제점이 있다:

  • 매크로 매개변수(macro parameter)가 겸용 자료형으로 되어있으면 컴파일러가 식별할 방법이 없다. 매크로는 어떤 특별한 타입 검사도 없이 확장된다.
  • i, j 매개변수는 두 번 비교된다. 예를 들어, 만약 두 매개변수가 둘 다 후위증가 변수를 가지고 있으면 증가 연산(incerement)은 두 번 작동할 것이다.
  • 매크로는 전처리기에 의해 확장되기 때문에, 컴파일러 에러 메시지는 매크로 정의 자체가 아니라 확장된 매크로를 참조할 것이다. 물론, 매크로는 디버깅 중에 확장된 형태로 나타날 것이다.

 

Templates and Void Pointers (템플릿과 void 포인터)

 

void 포인터와 함께 사용되고 있는 많은 함수들은 템플릿으로도 사용 가능하다. void 포인터는 알 수 없는 타입의 데이터를 연산하는 함수를 허용하기 위해 종종 사용된다. void 포인터를 사용 할 때, 컴파일러는 타입을 구별할 수 없어서 타입-특성(type-specific) 연산자 사용, 연산자 오버로딩, 생성자 또는 소멸자와 같은 타입 검사나 타입-특성 동작을 할 수 없게 된다.

 

템플릿을 사용하면, 타입이 결정된 자료를 연산할 수 있는 함수나 클래스를 만들 수 있다. 타입은 템플릿 정의에서 추상화된 것으로 보이지만, 컴파일 타임에 컴파일러는 각 타입 특성에 맞는 함수의 버전을 각기 따로 생성한다. 이것은 컴파일러가 타입 특성에 따라 동작하려고 하는 클래스나 함수를 다룰 수 있도록 한다. 또한 구조체처럼 복잡한 여러 타입들에 대해 특별한 경우를 만들 필요가 없게 해 주기 대문에 템플릿은 코드의 명확성(clarity)도 향상시킨다.

 

Templates and Smart Pointers (템플릿과 스마트 포인터)

 

 C++는 포인터를 캡슐화하고 연산 포인터에 기능을 추가하는 포인터 오버라이드된 스마트 포인터 클래스 생성을 허용한다. 템플릿은 거의 대부분의 타입을 가리키는 포인터를 캡슐화하는 일반적인 래퍼(wrapper) 생성을 허용한다.

 

다음의 코드는 간단한 쓰레기 수집기(garbage collector) 참조 횟수를 보여준다. Ptr<T> 템플릿 클래스는 RefCount로부터 파생된 어떠한 클래스에서도 쓰레기 수집기 포인터를 사용할 수 있게 한다.

 

Example

// templates_and_smart_pointers.cpp
#include <stdio.h>

#define TRACE printf

class RefCount {
   int crefs;
public:
   RefCount(void) {
      crefs = 0;
   }

   ~RefCount() {
      TRACE("goodbye(%d)\n", crefs);
   }

   void upcount(void) {
      ++crefs;
      TRACE("up to %d\n", crefs);
   }

   void downcount(void)
   {
      if (--crefs == 0)
         delete this;
   else
      TRACE("downto %d\n", crefs);
   }
};


class Sample : public RefCount {
public:
   void doSomething(void) {
      TRACE("Did something\n");
   }
};


template <class T> class Ptr {
   T* p;
public:
   Ptr(T* p_) : p(p_) {
      p->upcount();
   }

   ~Ptr(void) {
      p->downcount();
   }

   operator T*(void) {
      return p;
   }

   T& operator*(void) {
      return *p;
   }

   T* operator->(void) {
      return p;
   }

   Ptr& operator=(Ptr<T> &p_) {
      return operator=((T *) p_);
   }

   Ptr& operator=(T* p_) {
      p_->upcount();
      p->downcount();
      p = p_;
      return *this;
   }

   Ptr(const Ptr<T> &p_) {
      p = p_.p;
      p->upcount();
   };
};


int main() {
   Ptr<Sample> p  = new Sample; // sample #1
   Ptr<Sample> p2 = new Sample; // sample #2
   p = p2; // #1 will have 0 crefs, so it is destroyed;
         // #2 will have 2 crefs.
   p->doSomething();
   return 0;
   // As p2 and p go out of scope, their destructors call
   // downcount. The cref variable of #2 goes to 0, so #2 is
   // destroyed
}


 

Output

up to 1
up to 1
up to 2
goodbye(0)
Did something
downto 1
goodbye(0)


 

 

 RefCountPtr<T> 클래스는 둘 다 RefCount 로부터 상속한 인스턴스 부담(instance overhead)마다 int에 영향을 주는 어떤 클래스든지 간단한 쓰레기 수집 솔루션을 제공한다. Ptr처럼 일반적인 클래스 대신에 Ptr<T>같은 매개변수를 가지는 클래스 사용의 주요한 이득은 완벽히 typesafe 하다는 것이다. 앞의 코드는 Ptr<T>가 거의 어떤 곳에서도 T*로 사용되는 것을 보장한다. 반면에, 일반적인 Ptr은 단순히 void*형으로 암묵적인(implicit) 변환만 제공할 것이다.

 

클래스가 쓰레기 수집된 파일, 심볼(symbols), 문자열(strings) 등을 생성하고 조작하는 것을 고려해보아라. Ptr<T> 클래스 템플릿으로부터 컴파일러는 Ptr<File>, Ptr<Symbol>, Ptr<String> 등의 템플릿 클래스들을 만들 것이다. 그 클래스들의 멤버 함수로는 Ptr<File>::~Ptr(), Ptr<File>::operator File*(), ptr<String>::~Ptr(), Ptr<String>::operator String*() 등이 있을 것이다.

 

Templates and Collection Classes (템플릿과 콜렉션 클래스)

 

템플릿은 콜렉션 클래스를 도구로 삼기에 좋은 방법이다.

// templates_and_collection_classes.cpp
template <class T, int i> class MyStack
{
   T StackBuffer[i];
   int cItems;
public:
   MyStack( void ) : cItems( i )
   {
   };
   void push( const T item );
   T pop( void );
};

template <class T, int i> void MyStack< T, i >::push( const T item )
{
   if( cItems > 0 )
      StackBuffer[--cItems] = item;
   else
      throw "Stack overflow error.";
}

template <class T, int i> T MyStack< T, i >::pop( void )
{
   if( cItems < i )
      return StackBuffer[cItems++]
   else
      throw "Stack underflow error.";
}

int main()
{
   MyStack<char , 1> v;
   v.push('a');
}

Comments

MyStack 콜렉션은 스택의 간단한 구현(implementation)이다. T와 i 두 템플릿 매개변수는 스택에서 원소의 자료형과 최대 항목 갯수를 조건으로 지정한다. push와 pop 멤버 함수는 스택에 바닥에서부터 차오르도록 스택 상에서 항목을 넣거나 뺀다.

'Programming Languages > C++ Templates' 카테고리의 다른 글

Template Specifications  (0) 2010.05.10
Templates Overview  (0) 2010.05.10
Templates  (0) 2010.05.09
Posted by 독뽀
,

템플릿 선언은 매개변수화 클래스(parameterized class)나 함수의 집합을 상세히 기술한다.

 template<template-parameter-list> declaration

Remarks

template-parameter-list 는 템플릿 매개변수의 콤마(,)로 구별된 리스트이다. 이들은 classidentifier, typenameidentifier, template < template-parameter-list  > class identifier 등의 형식으로 타입을 나타내거나 템플릿의 본문에서 사용되어질 비(非)-타입 매개변수(non-type parameters)일 것이다.
템플릿 매개변수를 위한 문법의 한 예는 다음과 같다.

 parameter-declaration
 class identifier [ = typename ]
 typename identifier [ = typename ]
 template<template-parameter-list> class [identifier][= name]

일반적인 클래스의 인스턴스화(instantiate)보다 원하는대로 더 인스턴스화 할 수 있지만, 꺾은 괄호(< >) 속에 템플릿 인자(template arguments)를 반드시 포함시켜야한다. 이 템플릿 인자는 템플릿 인자의 나열 중 class, typename 키워드, 또는 인자가 비타입 인자의 경우 적당한 타입의 값을 포함한다면, 어떠한 타입으로도 될 수 있다. 이처럼 함수 템플릿을 호출하기 위해 특수한 문법을 요구하지 않음에도 불구하고, 템플릿 매개변수가 인자로부터 함수를 추론할 수 없다면 꺾은 괄호와 템플릿 인자를 요구할 것이다.

template-parameter-list 는 템플릿 함수에 의해 사용되는 매개변수의 목록이며, 뒤따르는 코드 일부분의 특성은 변할 것이다. 예를 들면:

 template<class T, int i> class MyStack...

이 경우, 템플릿은 타입(class T)과 상수 매개변수(constant parameter : int i)를 받을 수 있다. 템플릿은 인스턴스화에 타입 T와 상수형 정수 i를 사용할 것이다. MyStack 선언의 본문에서 T 식별자를 반드시 참조해야한다.

템플릿 선언 자체는 코드를 생성하지 않는다: 단지 클래스와 함수의 집합체를 서술할 뿐이며, 다른 코드를 참조할 때 하나 혹은 여러 개가 생성될 것이다.

템플릿 선언은 전역(global), 네임스페이스(namespace) 혹은 클래스 범위(class scope)를 가진다. 이들은 함수 외에는 선언될 수 없다.

다음 예는 타입 매개변수 T와 비-타입 템플릿 매개변수 i와 함께 클래스 템플릿의 선언, 정의, 인스턴스화를 묘사한다.

 // template_specifications1.cpp
 template<class T, int i> class TestClass
 {
 public:
    char buffer[i];
    T testFunc(T* p1 );
 };

 template<class T, int i>
 T TestClass<T,i>::testFunc(T* p1)
 {
     return *(p1++)
 };

 // To create an instance of TestClass
 TestClass<char, 5> ClassInst;
 int main()
 {
 ...
 }


Non-type template arguments (비-타입 템플릿 인자)

비-타입 템플릿 인자는 반드시 정수형(integral), 열거형(enumeration), 포인터, 참조형(reference) 또는 멤버 타입을 가리키는 포인터여야만 하며, 컴파일 타임에 상수화 되어야한다. 이들은 const나 volatile 타입으로 한정 지어질 수 있다. 부동 소수점 값은 템플릿 인자로 허용되지 않는다. 클래스의 객체나 구조체(struct) 또는 공용체(union)는 템플릿 인자로 허용되지 않지만, 그런 객체를 가리키는 포인터는 허용된다. 배열은 포인터로 변환되어 비-타입 템플릿 인자로 통용된다. 비-타입 인자로 통용되는 함수는 함수 포인터(function pointer)로 다뤄진다. 문자열 상수(String literal)는 템플릿 인자로 허용되지 않는다.

Using typename in a Template Declaration (템플릿 선언에서 typename 사용하기)

typename 키워드는 템플릿 인자 목록에서 사용될 수 있다. 다음 템플릿 선언은 동일하다.

 template<class T1, class T2> class X...
 template<typename T1, typename T2> class X...

Default Arguments for Template Parameters (템플릿 인자의 디폴트 인자)

클래스 템플릿은 = 기호 다음에 디폴트 타입이나 값을 통해 디폴트 인자를 가질 수 있다. 함수 템플릿은 디폴트 인자를 가질 수 없다. 나중에 클래스 템플릿을 위한 디폴트 인자(Default Arguments For Class Templates)에서 자세히 살펴보자.

 template<typename Type> class allocator {};
 template<typename Type, typename Allocator = allocator<Type>> class stack
 {
 };
 stack<int> MyStack;

Reuse of Template Parameters (템플릿 인자 재사용)

템플릿 인자는 템플릿 인자 목록에서 재사용될 수 있다. 다음과 같은 코드는 허용되는 예이다.

  // template_specifications2.cpp

 class Y
 {
 };
 template<class T, T* pT> class X1
 {
 };
 template<class T1, class T2 = T1> class X2
 {
 };

 Y aY;

 X1<Y, &aY> x1;
 X2<int> x2;

 int main()
 {
 }


Template template parameters (템플릿 템플릿 인자)

템플릿 인자는 자체가 템플릿이 될 수 있다. 이 생성자는 템플릿으로부터 생성된 클래스가 아니라 인자 자체가 템플릿이 되는 것을 의미한다. 다음 예는 템플릿 템플릿 인자를 위한 템플릿 인자의 A라는 이름은 생략될 수 있다. 왜냐하면 사용할 방법이 없기 때문이다.

 // template_specifications3.cpp
 #include <stdio.h>

 template<class T> struct str1
 {
    T t;
 };
 
 template<template<class A> class T> struct str2
 {
     T<int> t;
 };

 int main()
 {
     str2<str1> mystr2;
     mystr2.t.t = 5;
     printf_s("%d\n", mystr2.t.t);
 }


[출력 결과]

5

References as Template Parameters (템플릿 인자처럼 참조)

Visual Studio .NET 2003 은 비-타입 템플릿 인자처럼 참조하여 사용하는 기능을 소개했다. 이는 이전 버전에서는 허용되지 않았다.

 // references__supported_as_nontype_template_parameters.cpp
 #include <stdio.h>

 extern "C" int printf_s(const char*,...);
 template<int & ri> struct S
 {
    S()
    {
       printf_s("ri is %d\n", ri);
    }

    ~S()
    {
       printf_s("ri is %d\n", ri);
    }
 };

 int i = 1;

 int main()
 {
    S<i> s;
    i = 0;
 }


[출력 결과]

ri is 1
ri is 0

Nested Template Instances (네스티드 템플릿 인스턴스) ; nested : 둥지를 튼 것처럼 이중으로 쌓인 모양

Visual Studio 2005보다 앞선 Visual Studio의 버전에서는 네스티드 템플릿 인스턴스가 선언되어질 때 템플릿 인자 목록 사이에 여백(whitespace) 삽입이 필요했다. 다음 문법은 Visual Studio 2005부터 허용되었다.

 // template_specifications4.cpp

 template<typename T>
 class A
 {
 };
 template<int n>
 class B
 {
 };

 int main()
 {
    A<B<22>>();
 }




흐아.. 이거 생각보다 빡쎄네;; 자연스럽게 써내려가기가 왜 이렇게 시간이 많이 필요하단 말이냐!! ㅜㅜ
다음부터는 좀 늦어지더라도 충분히 내껄로 다 만들고 올려야징


'Programming Languages > C++ Templates' 카테고리의 다른 글

Advantages of Templates [C++]  (0) 2010.08.31
Templates Overview  (0) 2010.05.10
Templates  (0) 2010.05.09
Posted by 독뽀
,

 때때로 매개변수형이라고 일컬어지는 템플릿은 형 매개변수에 기반을 두고 있는 함수와 클래스를 생성할 때의 메커니즘이다. 템플릿을 사용함으로써, 각각의 타입마다 분리된 클래스를 만들어야하는 대신 여러 자료형 연산을 하는 단일 클래스나 함수로 디자인 할 수 있다.

Remark

예) 템플릿을 사용하지 않고 두 매개변수 중 작은 값을 리턴하는 typesafe 함수를 생성하기 위해서는 다음과 같이 오버로드된 집합을 작성해야 할 것이다.
 // what_are_templates1.cpp
 // compile with: /c
 // min for ints
 int min( int a, int b ) {
    return ( a < b ) ? a : b;
 }
 // min for longs
 long min( long a, long b ) {
    return ( a < b ) ? a : b;
 }
 // min for chars
 char min( char a, char b ) {
    return ( a < b ) ? a : b;

템플릿을 사용하면, 하나의 함수 템플릿으로 위와 같은 중복을 감소시킬수 있다.
 // what_are_templates2.cpp
 // compile with: /c
 template <class T> T min( T a, T b ) {
    return ( a < b ) ? a : b;
 }

템플릿은 소스 코드의 크기를 충분히 의미있게 줄여주고 type safety를 감소시키지 않으면서 코드의 유연성을 증가시킨다.

다음은 템플릿의 두 가지 주요 타입이다(함수 템플릿과 클래스 템플릿). 앞의 예에서 min은 함수 템플릿이다. A 클래스 템플릿은 매개변수를 가진 클래스이다. 다음을 보자:

 // what_are_templates3.cpp
 template <class T> class A {
    T m_t;
    public:
       A(T t): m_t(t) {}
       void f(T t);
 };

 int main() {
    A<int> a(10);
 }


템플릿은 몇가지 큰 차이점을 제외하고는 다른 함수나 클래스처럼 선언되고 정의된다. 템플릿 선언은 함수나 클래스를 완전히 정의하지 않는다(클래스나 함수의 문법적 골격만을 정의). 실질적인 클래스나 함수는 instantiation(인스턴스화)라 불리는 프로세스에 의해 템플릿으로부터 만들어진다. 각각의 클래스나 함수 생성은 instantiation으로 참조된다.

클래스 템플릿 예:
 template <class T> struct A { . . . };

위와 같은 클래스 템플릿은 A<int>, A<char>, A<int*>, A<MyClass*> 등등 instantiate class로 사용될 수 있다.

클래스나 함수의 instantiation은  explicit나 implicit으로 사용될 수 있다. Explicit instantiation은 코드에서 템플릿이 생성될 버전을 불러오는 한 방법이다. Implicit instantiation은 포인터가 처음으로 사용되는 곳에서 필요에 따라 템플릿이 인스턴스화 되도록 허용한다.

템플릿은 템플릿 매개변수가 함수에 매개변수처럼 선언되는 경우 값 매개변수(value parameter)에 의해 매개변수화될 수도 있다.

 // what_are_templates4.cpp
 // compile with: /EHsc
 #include <iostream>
 using namespace std;

 template <int i> class A {
    int array[i];
 public:
    A() { memset(array, 0, i*sizeof(int)); }
 };

 int main() {
    A<10> a;
 }


일반적인 템플릿 사용의 문제는 템플릿이 모든 솔루션에 하나의 크기로 맞춰져있다는 것이다. 이는 같은 코드는 모든 타입에 동일하게 적용된다는 뜻이다. 특정 자료형을 위한 템플릿의 동작을 변경할 필요가 있다면, 다양한 자료형의 매개변수를 가지면서 모든 매개변수가 아니라 특정 몇몇의 매개변수에 대한 동작만 변경하고 싶은 템플릿을 보유하고 있을 때 유용한 템플릿 특수화(template specialization)을 사용할 수 있다. 부분 특수화(a partial specialization)는 여전히 일반적이며, 실제 인스턴스 템플릿을 생산하기 위해 실재하는 템플릿 인수(real template arguments)가 필요하다.

'Programming Languages > C++ Templates' 카테고리의 다른 글

Advantages of Templates [C++]  (0) 2010.08.31
Template Specifications  (0) 2010.05.10
Templates  (0) 2010.05.09
Posted by 독뽀
,

역시나 이번에도 번역겸 요약이다.

Microsoft Visual Studio 2010 Help Libarary를 참고하여 작성됨을 미리 밝혀둡니다.
저작권 등 문제가 된다면 꼭 메일 주세요!! 바로 삭제나 블라인드 조치 취하겠습니다. asgawa@gmail.com

Templates(이하 템플릿)

C++ 템플릿은 함수나 클래스의 구성을 정의할 수 있게 하며, 이는 유동적인 자료형(런타임 중 어느것이 결정될지 모르는)을 가진 함수나 클래스가 연산을 할 수 있게 한다. C++ 템플릿을 사용하는 Microsoft 도구는 ISO/ANSI C++ 기준을 따르고 있다.

자료형만 다르고 동일한 코드의 통합이 목표인 상황에서 템플릿을 사용하라.

1. 같은 알고리즘을 적용할 함수이고, 자료형만 다르게 적용하기를 요구하는 함수를 만들 때
2. typesafe class(자료형에 관해 안전한 클래스) 집합을 개발할 때

템플릿은 때때로 C 언어의 매크로와 void형 포인터보다 더 좋은 해결책이 되기도 하며, collections(MFC에서 템플릿이 사용되는 main중 하나)나 스마트 포인터로 작업을 할 때 특히 유용하다.



앞으로 추가될 내용들

Overview
   Provides general information about templates, or parameterized types, in Visual C++.
Specifications
   Provides a specification for a template declaration.
Advantages of Templates
   Describes advantages of C++ templates. 
typename
   Describes the typename keyword.
Referencing Templates [C++ Language]
   Provides a task showing how to reference templates in your code.
Angle Bracket Placement
   Describes how angle brackets are placed in templates.
Differences from Other Implementations
   Discusses Microsoft-specific implementations of templates.
Name Resolution
   Discusses the three types of names in template definitions.
Class Templates
   Describes how to use and work with class templates.
Function Templates
   Describes how to use and work with function templates.

 

'Programming Languages > C++ Templates' 카테고리의 다른 글

Advantages of Templates [C++]  (0) 2010.08.31
Template Specifications  (0) 2010.05.10
Templates Overview  (0) 2010.05.10
Posted by 독뽀
,