#include <stdio.h>
#include <tchar.h>
#include <math.h>

#define LENGTH       32
#define SIGN_BIT     31
#define EXPONENT_MSB 30
#define EXPONENT_LSB 23
#define MANTISSA_MSB 22
#define MANTISSA_LSB  0

float hex_to_float (unsigned int value)
{
 int   sign;
 int   exp;
 int   man;
 float result;

 sign = (value & (1 << SIGN_BIT)) != 0;
#pragma warning( push )
#pragma warning( disable : 4307 ) // '-' : integral constant overflow.
 exp  = ((value & ( (2<<EXPONENT_MSB) - (1<<EXPONENT_LSB) )) >> EXPONENT_LSB)
  - (1 << (EXPONENT_MSB - EXPONENT_LSB))
  - (MANTISSA_MSB - MANTISSA_LSB);
#pragma warning( pop )

 man  = ((value & ( (2<<MANTISSA_MSB) - (1<<MANTISSA_LSB) )) >> MANTISSA_LSB)
  + (2 << (MANTISSA_MSB - MANTISSA_LSB));

 result = man * pow((float)2, (float)exp) * (sign ? -1 : 1);

 return result;
}

int _tmain(int argc, _TCHAR* argv[])
{
 union
 {
  unsigned int n;
  float        f;
 } value;

 int   i;
 float f;


 value.f =(float)   0;
 f       =(float)-1.1;

 for (i=0; i<10; i++)
 {
  printf ("%+e=0x%08x:hex_to_float()=%+e \r\n", value.f, value.n, hex_to_float(value.n));
  value.f += f;
 }

 return 0;
}
-----------------------------------------------------------------------------
+0.000000e+000=0x00000000:hex_to_float()=+0.000000e+000
-1.100000e+000=0xbf8ccccd:hex_to_float()=-1.100000e+000
-2.200000e+000=0xc00ccccd:hex_to_float()=-2.200000e+000
-3.300000e+000=0xc0533334:hex_to_float()=-3.300000e+000
-4.400000e+000=0xc08ccccd:hex_to_float()=-4.400000e+000
-5.500000e+000=0xc0b00000:hex_to_float()=-5.500000e+000
-6.600000e+000=0xc0d33333:hex_to_float()=-6.600000e+000
-7.700000e+000=0xc0f66666:hex_to_float()=-7.700000e+000
-8.800000e+000=0xc10ccccd:hex_to_float()=-8.800000e+000
-9.900001e+000=0xc11e6667:hex_to_float()=-9.900001e+000


-----------------------------------------------------------------------------

부동소수점 표현의 국제표준은 IEEE 754입니다.

-----------------------------------------------------------------------------

< float >
C의 float타입은 IEEE 754의 single precision 플로팅포인트를 구현한 것으로,
다음과 같은 포맷을 가집니다.
sign : bit31 (1비트)
exponent : bit30~bit23 (8비트)
mantissa : bit22~bit0 (23비트)

이때, 가수부(만티사)는 정수부분을 1로 정규화한 2진소수표현이며, 지수부(exponent)는
원래 지수에 바이어스 127을 더한 값입니다.
부호비트는 0이면 양수, 1이면 음수입니다.

가수부의 23비트가 100 0000 0000 0000 0000 0000 이라면, 이때 이 부동소수의 가수는
2진소수로 1.1이 되어, 10진법으로는 1 + 1/2 = 1.5가 됩니다.

지수부의 표현이 1000 0000 이라면, 이 값은 바이어스 127, 즉 111 1111이 더해진 수
이므로 실제 지수는 128 - 127 = 1이 됩니다.

따라서, 0 100 0000 100 0000 0000 0000 0000 0000 으로 표현되는 부동소수는
따라서, [0] [100 0000 0] [100 0000 0000 0000 0000 0000] 으로 표현되는 부동소수는
1.5 * 2^1 = 3.0 을 표현하게 됩니다.

single precision의 유효숫자는 가수의 비트길이 (정수부분 포함)24에 의해 결정되며,
2^24 은 약 10^7.2 이므로, 유효숫자는 약 7자리가 됩니다.

-----------------------------------------------------------------------------

< double >
C의 double타입은 IEEE 754의 double precision 플로팅포인트를 구현한 것으로,
다음과 같은 포맷을 가집니다.
sign : bit63 (1비트)
exponent : bit62~bit52 (11비트)
mantissa : bit51~bit0 (52비트)

이때, single precision과는 지수부의 바이어스가 1023이라는 것만 다르고, 나머지
표현방법은 동일합니다.

double precision의 유효숫자 역시 정수부분을 포함한 가수의 비트길이 53에 의해 결정되며,
2^53 은 약 10^15.9 이므로, 유효숫자는 약 약 15자리가 됩니다.

-----------------------------------------------------------------------------

< 예외 정의 >
1. 플로팅포인트 표현에서 모든 비트가 0인 수는 0으로 정의합니다.
2. 지수부의 모든 비트가 0인 수는 가수의 정수부분을 0으로 계산합니다.
3. 지수부의 모든 비트가 1이고, 가수부의 모든 비트가 0이면 무한대로 정의합니다.
4. 지수부의 모든 비트가 1이고, 가수부가 0이 아니면 NaN (Not a Number)로 정의하여
   예외를 발생하게 됩니다.


Posted by 셈말짓기 :

#include <windows.h>
#include <tchar.h>


#include <iostream>
#include <memory>

class o_1
{
public:
 o_1 () : a_ (0) { std::cout << "o_1()"  << std::endl; }
 virtual ~o_1( ) { std::cout << "~o_1()" << std::endl; }
public:
 virtual void show (void)
 {
  std::cout << "o_1::show("<< a_ <<")" << std::endl;
 }
public:
 int a_;
};

class o_2 : public o_1
{
public:
 o_2 () : o_1(), b_(0) { std::cout << "o_2()"  << std::endl; }
 virtual ~o_2()        { std::cout << "~o_2()" << std::endl; }
public:
 virtual void show (void)
 {
  std::cout << "o_2::show("<< b_ <<")" << std::endl;
 }
public:
 int b_;
};

class o_3 : public o_2
{
public:
 o_3 () : o_2(), c_(0) { std::cout << "o_3()"  << std::endl; }
 virtual ~o_3()        { std::cout << "~o_3()" << std::endl; }
public:
 virtual void show (void)
 {
  std::cout << "o_3::show("<< c_ <<")" << std::endl;
 }
public:
 int c_;
};

unsigned int vftable_of____o_1;
unsigned int vftable_of____o_2;
unsigned int vftable_of____o_3;

unsigned int get__vfp  (void* p)
{
 unsigned int __vfp = 0;

 memcpy (&__vfp, p, 4);

 return __vfp;
}

#pragma warning( push )
#pragma warning( disable: 4313 )
// C4313: 'printf' : '%x' in format string conflicts with argument 1 of type 'xxx'

void init (void)
{
 o_1 *o1=new o_1();
 o_2  o2;
 o_3 *o3=new o_3();

 memcpy (&vftable_of____o_1,  o1, 4);
 memcpy (&vftable_of____o_2, &o2, 4);
 memcpy (&vftable_of____o_3,  o3, 4);

 printf (" \r\n");
 printf ("# o_1::vftable_of____o_1=0x%08x \r\n", vftable_of____o_1);
 printf ("# o_2::vftable_of____o_2=0x%08x \r\n", vftable_of____o_2);
 printf ("# o_3::vftable_of____o_3=0x%08x \r\n", vftable_of____o_3);
 printf (" \r\n");

 delete o1;
 delete o3;
}

void test (void)
{
 o_3 *o = new o_3();
 o_1 *p = o;

 o->a_ = 100;
 o->b_ = 200;
 o->c_ = 300;

 printf (" p    's address=0x%08x \r\n", p);
 printf (" p->a_'s address=0x%08x \r\n", &o->a_);
 printf (" p->b_'s address=0x%08x \r\n", &o->b_);
 printf (" p->c_'s address=0x%08x \r\n", &o->c_);
 p->show ();

 printf (" \r\n");
 printf ("# p's __vfp 0x%08x \r\n", get__vfp(p));
 printf (" \r\n");
 printf ("# p->~o_1() \r\n");
 p->~o_1();
 printf (" \r\n");
 printf ("# p's __vfp 0x%08x \r\n", get__vfp(p));
 printf (" \r\n");
 p->show ();

 printf (" \r\n");
 printf ("# let's get fun! \r\n");
 memcpy (p, &vftable_of____o_3, 4); p->show ();
 memcpy (p, &vftable_of____o_2, 4); p->show ();
 memcpy (p, &vftable_of____o_1, 4); p->show ();


 int   v;
 char *member_variable_ptr;

 member_variable_ptr = (char*)p;

 v = 99;
 member_variable_ptr += 4;
 printf (" \r\n");
 printf ("# one more time! (member_variable_ptr=0x%08x) \r\n", member_variable_ptr);
 memcpy (member_variable_ptr, &v, 4);
 memcpy (p, &vftable_of____o_3, 4); p->show ();
 memcpy (p, &vftable_of____o_2, 4); p->show ();
 memcpy (p, &vftable_of____o_1, 4); p->show ();

 v = 98;
 member_variable_ptr+= 4;
 printf (" \r\n");
 printf ("# one more time! (member_variable_ptr=0x%08x) \r\n", member_variable_ptr);
 memcpy (member_variable_ptr, &v, 4);
 memcpy (p, &vftable_of____o_3, 4); p->show ();
 memcpy (p, &vftable_of____o_2, 4); p->show ();
 memcpy (p, &vftable_of____o_1, 4); p->show ();

 v = 97;
 member_variable_ptr+= 4;
 printf (" \r\n");
 printf ("# one more time! (member_variable_ptr=0x%08x) \r\n", member_variable_ptr);
 memcpy (member_variable_ptr, &v, 4);
 memcpy (p, &vftable_of____o_3, 4); p->show ();
 memcpy (p, &vftable_of____o_2, 4); p->show ();
 memcpy (p, &vftable_of____o_1, 4); p->show ();


 printf (" \r\n");
 printf ("# last time ! \r\n");
 memcpy (p, &vftable_of____o_3, 4);

 delete p;
}

#pragma warning( pop )


int _tmain(int argc, _TCHAR* argv[])
{
 std::cout << "==============================================================" <<std::endl;
 std::cout << "init()" <<std::endl;
 std::cout << "==============================================================" <<std::endl;
 init ();
 std::cout << "==============================================================" <<std::endl;
 std::cout <<std::endl;
 std::cout <<std::endl;
 std::cout <<std::endl;


 std::cout << "==============================================================" <<std::endl;
 std::cout << "test()" <<std::endl;
 std::cout << "==============================================================" <<std::endl;
 test ();
 std::cout << "==============================================================" <<std::endl;
 std::cout <<std::endl;
 std::cout <<std::endl;
 std::cout <<std::endl;

 return 0;
}
-----------------------------------------------------------------------------
==============================================================
init()
==============================================================
o_1()
o_1()
o_2()
o_1()
o_2()
o_3()

# o_1::vftable_of____o_1=0x00418890
# o_2::vftable_of____o_2=0x004188c4
# o_3::vftable_of____o_3=0x004188f4

~o_1()
~o_3()
~o_2()
~o_1()
~o_2()
~o_1()
==============================================================


==============================================================
test()
==============================================================
o_1()
o_2()
o_3()
 p    's address=0x003a6858
 p->a_'s address=0x003a685c
 p->b_'s address=0x003a6860
 p->c_'s address=0x003a6864
o_3::show(300)

# p's __vfp 0x004188f4

# p->~o_1()
~o_3()
~o_2()
~o_1()

# p's __vfp 0x00418890

o_1::show(100)

# let's get fun!
o_3::show(300)
o_2::show(200)
o_1::show(100)

# one more time! (member_variable_ptr=0x003a685c)
o_3::show(300)
o_2::show(200)
o_1::show(99)

# one more time! (member_variable_ptr=0x003a6860)
o_3::show(300)
o_2::show(98)
o_1::show(99)

# one more time! (member_variable_ptr=0x003a6864)
o_3::show(97)
o_2::show(98)
o_1::show(99)

# last time !
~o_3()
~o_2()
~o_1()

==============================================================

Posted by 셈말짓기 :

파괴자를 직접 부르면 어떻게 될까?

object o;

o.~object();

궁금해졌다.

-----------------------------------------------------------------------------
#include <windows.h>
#include <tchar.h>

#include <iostream>

class o_1
{
public:
 o_1 ()         { std::cout << "o_1()"  << std::endl; }
 virtual ~o_1() { std::cout << "~o_1()" << std::endl; }
};

class o_2 : public o_1
{
public:
 o_2 () : o_1() { std::cout << "o_2()"  << std::endl; }
 virtual ~o_2() { std::cout << "~o_2()" << std::endl; }
};

class o_3 : public o_2
{
public:
 o_3 () : o_2() { std::cout << "o_3()"  << std::endl; }
 virtual ~o_3() { std::cout << "~o_3()" << std::endl; }
};

void test1 (void)
{
 o_3  o;

 o_1* p = &o;

 std::cout << "-----------" <<std::endl;
 p->~o_1 ();
 std::cout << "-----------" <<std::endl;
}

void test2 (void)
{
 o_1* p = new o_3 ();

 std::cout << "-----------" <<std::endl;
 p->~o_1 ();
 std::cout << "-----------" <<std::endl;

 delete p;
}

void test3 (void)
{
 o_1* p = new o_3 ();

 std::cout << "-----------" <<std::endl;
 //p->~o_1 ();
 std::cout << "-----------" <<std::endl;

 delete p;
}

int _tmain(int argc, _TCHAR* argv[])
{
 std::cout << "###########" <<std::endl;
 test1();
 std::cout << "###########" <<std::endl;
 test2();
 std::cout << "###########" <<std::endl;
 test3();
 std::cout << "###########" <<std::endl;

 return 0;
}
-----------------------------------------------------------------------------
###########
<- test1() 함수: 잘된다...
o_1()
o_2()
o_3()
-----------
~o_3()
~o_2()
~o_1()
-----------
~o_3()
~o_2()
~o_1()
########### <- test2() 함수: 무엇인가 이상하다???
o_1()
o_2()
o_3()
----------- <- p->~o_1 (); 호출 부분... 부모 클래스 파괴자를 호출한다.
~o_3()
~o_2()
~o_1()
----------- <- delete p; 가 이상하다 = _=??? 무엇일까...
~o_1()
########### <- test3() 함수:
o_1()
o_2()
o_3()
-----------
<- //p->~o_1 ();
-----------   
주석처리 했더니 delete p; 가 제대로 동작한다.
~o_3()
~o_2()
~o_1()
###########
계속하려면 아무 키나 누르십시오 . . .
-----------------------------------------------------------------------------
디버깅을 해보았다.

p->~o_1(); 호출하기전 __vfptr(virtual fucntion pointer) 녀석은 이렇게 가리키고 있었다.

사용자 삽입 이미지

하지만, p->~o_1();을 호출하니 __vfptr 녀석은 이렇게 바뀌어 버렸다.
사용자 삽입 이미지

         test1()역시 p->~o_1();를 수행하면 p의 __vfptr 값도 동일하게 바뀌었다.               


고심끝에 내린 결론은

test1()에서 Stack에 생성된 객체는 파괴될때 가상함수-파괴자를 사용하지 않고 파괴 되므로
위와같은 결과를 얻었고,

test2()에서 Heap에 생성된 객체는 파괴되기전에 직접 p->~o_1(); 호출 하여 __vfptr이
변경됨으로서 delete p;에서 가상함수-파괴자를 이용한 파괴자 호출이 제대로 되지 못하는
것이다.

__vfptr이 변경 되므로 가상함수들이 제대로 동작을 안할 것이라 판단 되었다.
그래서, 소스 코드를 수정해서 다시 테스트 해보았다.
-----------------------------------------------------------------------------
#include <windows.h>
#include <tchar.h>

#include <iostream>

class o_1
{
public:
 o_1 ()         { std::cout << "o_1()"  << std::endl; }
 virtual ~o_1() { std::cout << "~o_1()" << std::endl; }
public:
 virtual void show (void)
 {
  std::cout << "o_1::show()" << std::endl;
 }

};

class o_2 : public o_1
{
public:
 o_2 () : o_1() { std::cout << "o_2()"  << std::endl; }
 virtual ~o_2() { std::cout << "~o_2()" << std::endl; }
public:
 virtual void show (void)
 {
  std::cout << "o_2::show()" << std::endl;
 }

};

class o_3 : public o_2
{
public:
 o_3 () : o_2() { std::cout << "o_3()"  << std::endl; }
 virtual ~o_3() { std::cout << "~o_3()" << std::endl; }
public:
 virtual void show (void)
 {
  std::cout << "o_3::show()" << std::endl;
 }

};

void test1 (void)
{
 o_3  o;

 o_1* p = &o;

 std::cout << "-----------" <<std::endl;
 p->show ();
 o.show();
 std::cout << "-----------" <<std::endl;
 p->~o_1 ();
 std::cout << "-----------" <<std::endl;
 p->show ();
 o.show();
 std::cout << "-----------" <<std::endl;
}

void test2 (void)
{
 o_1* p = new o_3 ();

 std::cout << "-----------" <<std::endl;
 p->~o_1 ();
 std::cout << "-----------" <<std::endl;

 delete p;
}

void test3 (void)
{
 o_1* p = new o_3 ();

 std::cout << "-----------" <<std::endl;
 //p->~o_1 ();
 std::cout << "-----------" <<std::endl;

 delete p;
}

int _tmain(int argc, _TCHAR* argv[])
{
 std::cout << "###########" <<std::endl;
 test1();
 std::cout << "###########" <<std::endl;
 test2();
 std::cout << "###########" <<std::endl;
 test3();
 std::cout << "###########" <<std::endl;

 return 0;
}
-----------------------------------------------------------------------------
########### <- test1() 함수: 잘되는게 아니었다.
o_1()
o_2()
o_3()
-----------
o_3::show() <- p->show (); 정상이다.
o_3::show() <- o.show();   정상이다.
-----------
~o_3()
~o_2()
~o_1()
-----------
o_1::show() <- p->show ();      __vfptr이 변경되었으므로 제대로 동작을 못한다.     
o_3::show() <- o.show();
-----------
~o_3()
~o_2()
~o_1()
########### <- test2() 함수:
o_1()
o_2()
o_3()
-----------
~o_3()
~o_2()
~o_1()
-----------
~o_1()
########### <- test3() 함수:
o_1()
o_2()
o_3()
-----------
-----------
~o_3()
~o_2()
~o_1()
###########
계속하려면 아무 키나 누르십시오 . . .

-----------------------------------------------------------------------------
처음에는 컴파일러 버그라고 생각되었지만 곰곰히 따져보니 아닌 것 같다.
설마, 진짜 컴파일러 버그는 아니겠지... = _ =;

[사용 컴파일러]
Microsoft Visual Studio 2005
Version 8.0.50727.762  (SP.050727-7600)
Microsoft .NET Framework
Version 2.0.50727 SP1

Installed Edition: Professional

-----------------------------------------------------------------------------
추가:
데브피아에 올렸보았었는데 오해하실 수 있는 부분 있는거 같아서 추가합니다.

제가 말하고 싶었던것은 소멸자를 직접 호출했을경우 vftable을 가리키는 __vfptr이
변경된다는 걸 말하고 싶었던겁니다.

좀 더 부연설명을 하자면 메모리 풀 같은 걸 만들때 메모리 풀에서 받은 객체를 사용하고 삭제
후 그대로 또 사용했을 경우 일어나는 현상이 어떻게 될것인가 따져보는 의미입니다.

위의 코드는 일종의 toy code입니다.


제가 컴파일러 버그가 아닐까라고 생각한 부분은 직접 파괴자(소멸자)가 호출된다고 해서
메모리에서 실제로 delete가 일어나는 건 아니기 때문에 vftable을 가리키는 __vfptr가
변경되는게 맞는건지 아닌지
잘 판단이 안되었기 때문에 적어 놓은겁니다.


 

Posted by 셈말짓기 :

Reference-Counting

2008. 8. 18. 13:24 from 셈말짓기/C and C++

#include <windows.h>
#include <tchar.h>

#include <iostream>

/////////////////////////////////////////////////////////////////////////////
//
// Handle
//
/////////////////////////////////////////////////////////////////////////////
template<typename T>
class CRefCountedInstance
{
public:
 CRefCountedInstance ();

public:
 inline void AddRef       (void);
 inline void Release      (void);
 inline void Assign       (T *p);
 inline bool IsReferenced (void);
 inline T*   GetInstance  (void);

private:
 T   *Instance_;
 int  RefCount_;
};

template<typename T>
CRefCountedInstance<T>::CRefCountedInstance () :
 RefCount_ (0),
 Instance_ (0)
{
}

template<typename T>
void CRefCountedInstance<T>::AddRef (void)
{
 RefCount_++;
}

template<typename T>
void CRefCountedInstance<T>::Release (void)
{
 if (RefCount_>0)
 {
  RefCount_--;
 }

 if (RefCount_==0)
 {
  if (Instance_)
  {
   delete Instance_;
  }

  Instance_ = 0;
 }
}

template<typename T>
void CRefCountedInstance<T>::Assign (T *p)
{
 Instance_ = p;
 AddRef ();
}

template<typename T>
bool CRefCountedInstance<T>::IsReferenced (void)
{
 if (RefCount_==0)
  return false;

 return true;
}

template<typename T>
T* CRefCountedInstance<T>::GetInstance (void)
{
 return Instance_;
}

template<typename T>
class Handle
{
public:
 Handle ();
 explicit Handle (T *p);
 Handle (const Handle<T> &copy);
 ~Handle ();

public:
 Handle<T>& operator = (const Handle<T>& rhs);

public:
 inline T& operator*  () const;
 inline T* operator-> () const;
 inline T* Get    (void) const;

private:
 CRefCountedInstance<T>* Rep_;
};

template<typename T>
Handle<T>::Handle () : Rep_(0)
{
}

template<typename T>
Handle<T>::Handle (T *p)
{
 Rep_ = new CRefCountedInstance<T>();
 Rep_->Assign(p);
}

template<typename T>
Handle<T>::Handle (const Handle<T> &copy)
{
 Rep_ = copy.Rep_;

 if (Rep_)
  Rep_->AddRef ();
}

template<typename T>
Handle<T>::~Handle ()
{
 if (Rep_)
 {
  Rep_->Release ();

  if (!Rep_->IsReferenced())
   delete Rep_;
 }
}

template<typename T>
Handle<T>& Handle<T>::operator = (const Handle<T>& rhs)
{
 if (this == &rhs) return *this;

 if (Rep_)
  Rep_->Release ();

 Rep_ = rhs.Rep_;

 if (Rep_)
  Rep_->AddRef ();

 return *this;
}

template<typename T>
T& Handle<T>::operator*() const
{
 return *(Rep_->GetInstance());
}

template<typename T>
T* Handle<T>::operator -> () const
{
 if (Rep_==0)
  return 0;

 return (Rep_->GetInstance());
}

template<typename T>
T* Handle<T>::Get (void) const
{
 if (Rep_==0)
  return 0;

 return (Rep_->GetInstance());
}


/////////////////////////////////////////////////////////////////////////////
//
// Application
//
/////////////////////////////////////////////////////////////////////////////
class Object
{
public:
 explicit Object(int n=0) : Data_(n)
 {
  std::cout << "Object(" << Data_ << ")" << std::endl;
 }

public:
 virtual ~Object()
 {
  std::cout << "~Object(" << Data_ << ")" << std::endl;
 }

public:
 int Data_;
};

Handle<Object> Test (Handle<Object> h)
{
 if (h.Get())
  h->Data_ = 3;

 return h;
}


/////////////////////////////////////////////////////////////////////////////
//
// Startup
//
/////////////////////////////////////////////////////////////////////////////
int _tmain(int argc, _TCHAR* argv[])
{
 Handle<Object> p1( new Object(1) );
 Handle<Object> p2( new Object(2) );
 Handle<Object> p3;
 Handle<Object> p4;


 std::cout << std::endl;


 std::cout << "p2 = p1;" << std::endl;
 p2 = p1;
 std::cout << std::endl;


 std::cout << "p3 = p1;" << std::endl;
 p3 = p1;
 std::cout << std::endl;


 std::cout << "p4 = Test (p3);" << std::endl;
 p4 = Test (p3);

 std::cout << "p1->Data_ = " << p1->Data_ << std::endl;
 std::cout << "p2->Data_ = " << p2->Data_ << std::endl;
 std::cout << "p3->Data_ = " << p3->Data_ << std::endl;
 std::cout << "p4->Data_ = " << p3->Data_ << std::endl;

 return 0;
}
-----------------------------------------------------------------------------
Object(1)
Object(2)

p2 = p1;
~Object(2)

p3 = p1;

p4 = Test (p3);
p1->Data_ = 3
p2->Data_ = 3
p3->Data_ = 3
p4->Data_ = 3
~Object(3)

Posted by 셈말짓기 :

//////////////////////////////////////////////////////////////////////////////////////
//
// 템플릿 클래스 메소드 특화
//
//
//////////////////////////////////////////////////////////////////////////////////////
#include <string>

#include <windows.h>

template <class CharType>
class Message
{
public:
 void Print (void);
 void Set   (std::basic_string < CharType > s);

public:
 std::basic_string < CharType > text_;
};

template <class CharType>
void Message<CharType>::Set (std::basic_string < CharType > s)
{
 text_ = s;
}

template <class CharType>
void Message<CharType>::Print (void)
{
 OutputDebugStringW (text_.c_str());
}

template <>
void Message<char>::Print (void)
{
 printf (text_.c_str());
}

int _tmain(int argc, _TCHAR* argv[])
{
 Message<wchar_t> b;

 b.Set (L"bbb\r\n");
 b.Print();


 Message<char> a;

 a.Set ("aaa\r\n");
 a.Print();


 return 0;
}
--------------------------------------------------------------------------------------
aaa (콘솔창)
--------------------------------------------------------------------------------------
bbb (디버깅창)





//////////////////////////////////////////////////////////////////////////////////////
//
// 템플릿 클래스 특화 (Specialization of template class)
//
//
//////////////////////////////////////////////////////////////////////////////////////
#include <windows.h>
#include <tchar.h>
#include <iostream>

template<class T>
class Min
{
public:
 const T& Is (const T &a, const T &b)
 {
  std::cout << "template<class T> class Min::Is ("
      << static_cast<int>(a) << ", "
      << static_cast<int>(b) << ")"
      << std::endl;

  return (a<b) ? a: b;
 }
};

template<>
class Min <char>
{
public:
 const char& Is (const char &a, const char &b)
 {
  std::cout << "template<> class Min<char>::Is ( \'"
      << a << "\', "
      << b << "\' )"
      << std::endl;

  return (a<b) ? a: b;
 }
};

int _tmain(int argc, _TCHAR* argv[])
{
 Min<int>  a;
 //Min<>     b; <- error
 Min<char> c;
 //Min<>     d; <- error

 a.Is (1,2);
 //b.Is (3,4);
 c.Is ('a','b');
 //d.Is ('c','d');

 return 0;
}
--------------------------------------------------------------------------------------
template<class T> class Min::Is (1, 2)
template<> class Min<char>::Is ( 'a', b' )





//////////////////////////////////////////////////////////////////////////////////////
//
// 함수 템플릿 특화 (Specialization of function template)
//
//
//////////////////////////////////////////////////////////////////////////////////////
#include <windows.h>
#include <tchar.h>
#include <iostream>

template<class T>
const T& Min (const T &a, const T &b)
{
 std::cout << "template<class T> const T& Min ("
           << static_cast<int>(a) << ", "
     << static_cast<int>(b) << ")"
     << std::endl;

 return (a<b) ? a: b;
}

template<>
const char& Min <char> (const char &a, const char &b)
{
 std::cout << "template<> const char& Min <char> ( \'"
           << a << "\', "
     << b << "\' )"
     << std::endl;

 return (a<b) ? a: b;
}

int _tmain(int argc, _TCHAR* argv[])
{
 Min<int>  ( 1 ,  2 );
 Min<>     ( 3 ,  4 );
 Min<char> ('c', 'd');
 Min<>     ('a', 'b');

 return 0;
}
--------------------------------------------------------------------------------------
template<class T> const T& Min (1, 2)
template<class T> const T& Min (3, 4)
template<> const char& Min <char> ( 'c', d' )
template<> const char& Min <char> ( 'a', b' )

//
// cf>
//   함수 템플릿은 아래와 같이 정의 할 수 있지만
//   template <class T, int X>
//   void foo_func (T a)
//   {
//   }
//   아래와 같이 기본 템플릿 인수는 정의 할 수 없다.
//   template <class T, int X=0>
//   void foo_func (T a)
//   {
//   }
//   기본 템플릿 인수는 클래스 탬플릿에서만 사용이 가능하다.
//
//   또한, 부분특화 템플릿 함수는 사용 될 수 없다.
//





//////////////////////////////////////////////////////////////////////////////////////
//
// 템플릿 클래스 부분특화 (Partial specialization of template class)
//
//
//////////////////////////////////////////////////////////////////////////////////////
#include <windows.h>
#include <tchar.h>
#include <iostream>

// partial specialization

class partial_specialization
{
public:
 partial_specialization ()
 {
  std::cout << "partial_specialization ()" << std::endl;
 }
 ~partial_specialization ()
 {
  std::cout << "~partial_specialization ()" << std::endl;
 }
};

template <class T1, class T2> class foo
{
public:
 foo ()
 {
  std::cout << "foo ()" << std::endl;
 }

 ~foo ()
 {
  std::cout << "~foo ()" << std::endl;
 }
};

template <class T1> class foo <T1, partial_specialization>
{
public:
 foo ()
 {
  std::cout << "foo() 2" << std::endl;
 }

 ~foo ()
 {
  std::cout << "~foo() 2" << std::endl;
 }
};

int _tmain(int argc, _TCHAR* argv[])
{
 foo<int, int>                    a;
 foo<int, partial_specialization> b;

 return 0;
}
--------------------------------------------------------------------------------------
foo ()
foo() 2
~foo() 2
~foo ()

Posted by 셈말짓기 :