20141103 (C++ Template 특수화, 부분 특수화, 인자, static, 예외처리, ARM PWM)

171일차









----------

C++

----------



------- Template 특수화, 부분 특수화


템플릿을 특수화하면 템플릿을 구성하는 멤버를 다르게 행동하도록 할 수 있다.

다음 예제 참고


예제)

#include <iostream>

#include <cstring>

using namespace std;


template <typename T>

class Point 

{

private:

T xpos, ypos;

public:

Point(T x=0, T y=0): xpos(x), ypos(y)

{  }

void ShowPosition() const

{

cout<<'['<<xpos<<", "<<ypos<<']'<<endl; 

}

};


template <typename T>

class SimpleDataWrapper 

{

private:

T mdata;

public:

SimpleDataWrapper(T data) : mdata(data)

{ }

void ShowDataInfo(void)

{

cout<<"Data: "<<mdata<<endl;

}

};


template<>

class SimpleDataWrapper <char*>

{

private:

char* mdata;

public:

SimpleDataWrapper(char* data)

{

mdata=new char[strlen(data)+1];

strcpy(mdata, data);

}

void ShowDataInfo(void)

{

cout<<"String: "<<mdata<<endl;

cout<<"Length: "<<strlen(mdata)<<endl;

}

~SimpleDataWrapper()

{

delete []mdata;

}

};


// Template 특수화

template<>

class SimpleDataWrapper <Point<int>>

{

private:

Point<int> mdata;

public:

SimpleDataWrapper(int x, int y) : mdata(x, y)

{ }

void ShowDataInfo(void)

{

mdata.ShowPosition();

}

};


int main(void)

{

SimpleDataWrapper<int> iwrap(170);

iwrap.ShowDataInfo();


SimpleDataWrapper<char*> swrap("Class Template Specialization");

swrap.ShowDataInfo();


SimpleDataWrapper<Point<int>> poswrap(3, 7);

poswrap.ShowDataInfo();

return 0;

}



위의 예제에서 확인할 수 있듯이 템플릿을 하면 컴파일러에서 자동으로 다른 타입의

함수를 생성해 주지만 특수한 경우는 따로 선언한 것을 사용하게 한 것을 특수화라 한다.





--- Template 부분 특수화


특수화와 같은데 쬐금 업그레이드(?) 된 것이다.


예제)

#include <iostream>

using namespace std;


template <typename T1, typename T2>

class MySimple 

public:

void WhoAreYou()

{

cout<<"size of T1: "<<sizeof(T1)<<endl;

cout<<"size of T2: "<<sizeof(T2)<<endl;

cout<<"<typename T1, typename T2>"<<endl;

}

};


template<>

class MySimple<int, double>

{

public:

void WhoAreYou()

{

cout<<"size of int: "<<sizeof(int)<<endl;

cout<<"size of double: "<<sizeof(double)<<endl;

cout<<"<int, double>"<<endl;

}

};



template<typename T1>

class MySimple<T1, double>

{

public:

void WhoAreYou()

{

cout<<"size of T1: "<<sizeof(T1)<<endl;

cout<<"size of double: "<<sizeof(double)<<endl;

cout<<"<T1, double>"<<endl;

}

};



int main(void)

{

MySimple<char, double> obj1;

obj1.WhoAreYou();

MySimple<int, long> obj2;

obj2.WhoAreYou();

MySimple<int, double> obj3;

obj3.WhoAreYou();

return 0;

}

결과














------- Template 인자


템플릿 매개변수의 선언에 마치 함수처럼 변수의 선언을 할 수 있다.


예제)

#include <iostream>


using namespace std;


template <typename T, int len> // 인자 선언

class SimpleArray

{

private:

T arr[len]; // 인자만큼 배열 할당


public:

T& operator[] (int idx)

{

return arr[idx];

}


SimpleArray<T, len>& operator=(const SimpleArray<T, len>& ref)

{

for(int i = 0; i < len; ++i)

{

arr[i] = ref.arr[i];

}

return *this;

}

};


int main()

{

SimpleArray<int, 5> i5arr1; // 객체에 int * 5 크기의 배열 멤버 할당

for(int i = 0; i < 5; ++i)

{

i5arr1[i] = i * 10;

}


SimpleArray<int, 5> i5arr2; // 객체에 int * 5 크기의 배열 멤버 할당

i5arr2 = i5arr1;

for(int i = 0; i < 5; ++i)

{

cout << i5arr2[i] << ", ";

}

cout << endl;


SimpleArray<int, 7> i7arr1; // 객체에 int * 7 크기의 배열 멤버 할당

for(int i = 0; i < 7; ++i)

{

i7arr1[i] = i * 10;

}


SimpleArray<int, 7> i7arr2; // 객체에 int * 7 크기의 배열 멤버 할당

i7arr2 = i7arr1;

for(int i = 0; i < 7; ++i)

{

cout << i7arr2[i] << ", ";

}

cout << endl;


return 0;

}

결과




설마 생각한 그것도 가능하다.

바로 인자에 디폴트 값 지정....


예제)

#include <iostream>


using namespace std;


template <typename T = int, int len = 7>

class SimpleArray

{

private:

T arr[len];

public:

T& operator[] (int idx)

{

return arr[idx];

}

T& operator=(const T&ref)

{

for(int i=0; i<len; i++)

arr[i]=ref.arr[i];

}

};


int main(void)

{

SimpleArray<> arr; // 아무 값도 안넣어 줬기 때문에 디폴트 값이 들어감.

for(int i = 0; i < 7; i++)

arr[i] = i + 1;

for(int i = 0; i < 7; i++)

cout << arr[i] << " ";

cout << endl;


return 0;

}

결과











------- Template과 static 멤버 변수


다음 예제 참고


예제)

#include <iostream>


using namespace std;


template <typename T>

class SimpleStaticMem

{

private:

static T mem; // static 변수 선언. 같은 타입끼리 공유함.


public:

void AddMem(int num)

{

mem = mem + num;

}


void ShowMem()

{

cout<<mem<<endl;

}

} ;


template <typename T> 

T SimpleStaticMem<T>::mem = 0; // class 내에 static 멤버는 꼭 전역에서 초기화 필수!!



int main(void)

{

SimpleStaticMem<int> obj1; // 같은 클래스 이기 때문에 mem을 공유함

SimpleStaticMem<int> obj2; // 같은 클래스 이기 때문에 mem을 공유함

obj1.AddMem(2); // 2 더함

obj2.AddMem(3); // 3 더함

obj1.ShowMem();


SimpleStaticMem<long> obj3; // 같은 클래스 이기 때문에 mem을 공유함

SimpleStaticMem<long> obj4; // 같은 클래스 이기 때문에 mem을 공유함

obj3.AddMem(100); // obj3에 100 더함

obj4.ShowMem(); // obj4에서 출력했지만 공유하기 때문에 100 출력


return 0 ;

}

결과












------- 예외처리

 

try, catch, throw 라는 것으로 예외 처리를 하면 가독성과 유지보수성을 높일 수 있다.


예제)

#include <iostream>


using namespace std;


int main()

{

int num1;

int num2;


cout << "두 개의 숫자 입력: ";

cin >> num1 >> num2;


try

{

if(num2 == 0)

{

throw num2;

}

cout << "나눗셈의 몫: " << num1/num2 << endl;

cout << "나눗셈의 나머지: " << num1%num2 << endl;

}

catch(int expn) // throw num2 값을 expn이 받음

{

cout << "제수는 " << expn << "이 될 수 없습니다." << endl;

cout << "프로그램을 다시 실행하세요." << endl;

}


cout << "end of main" << endl;


return 0;

}






















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

ARM

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


------- PWM


이번엔 TC device가 아닌 PWM device를 사용한다.






- Clock 주파수 신호 종류

   총 13가지 이다. 이 중에 선택하여 사용함.




- Timing도





Timing도를 설명하자면









예제 소스)

/* 14번 Pin에 물린 LED가 점점 어두워짐. */

#include "AT91SAM7S256.h"


#define MAX_DUTY 800

#define DFT_DUTY 100


void PWM3_Init(void);

void Delay_ms(unsigned int ms);

void PWM3_Duty(unsigned int uiDuty);


int main(void)

{

volatile unsigned int uiCnt;

volatile unsigned int uiDuty;

PWM3_Init();

uiDuty = DFT_DUTY;

while(1)

{

for(uiCnt = 0; 100000 > uiCnt; ++uiCnt); // 이 딜레이로 uiDuty의 값이

PWM3_Duty(uiDuty); // 변하는 시간이 된다. 이 시간이 길수록

// 바뀌는 시간도 느려진다.

if(uiDuty < MAX_DUTY)

{

uiDuty = uiDuty + 10;

}

else

{

uiDuty = DFT_DUTY;

}

}

return 0;

}




void PWM3_Init(void)

{

*AT91C_PMC_PCER = (1 << AT91C_ID_PWMC);  // PWM 전원 공급

*AT91C_PIOA_PPUDR = AT91C_PA14_PWM3; // Pull-up off

*AT91C_PIOA_BSR = AT91C_PA14_PWM3; // PWM3 output(Peripheral B모드 사용)

*AT91C_PIOA_PDR = 0xFFFFFFFF; // 모든 PIO비활성화


*AT91C_PWMC_MR = (0x00 << 24) | // PREB = MCK

(0x06 << 8) | // PREA = MCK/64

(0 << 16)  | // DIVB = Off

(30 << 0); // DIVA = 30

// 48Mhz / 64 = 750Khz

// 750Khz / 30 = 25Khz


*AT91C_PWMC_CH3_CMR = (0 << 8) | // CALG = 0, 톱니모양

(0 << 9) | // CPOL = 0, Low로 시작

(0 << 10)| // CPD = 0, duty

(0x0B); // CPRE = CLKA


*AT91C_PWMC_CH3_CDTYR = DFT_DUTY; // TC0 RA와 같은 기능

*AT91C_PWMC_CH3_CPRDR = MAX_DUTY; // TC0 RC와 같은 기능

*AT91C_PWMC_ENA = AT91C_PWMC_CHID3; // PWM Enable

}




void PWM3_Duty(unsigned int uiDuty)

{

if(MAX_DUTY < uiDuty)

{

uiDuty = MAX_DUTY;

}

*AT91C_PWMC_CH3_CUPDR = uiDuty;

// 출력 주파수 조절하기 위해 CDTY Reg를 바로 건들면 오류가 난다.

// CUPD Reg의 값을 바꾸면 다음 주기때 CDTY값이 바뀐다.

}


결과


(결과에 불 깜빡임을 보면 부드럽게 꺼지는데, 실제로 볼 경우 제법 깜빡임이 있다.)








위의 소스에서 아래와 같이 수정하면


#define MAX_DUTY (18750 * 2) // 초당 주파수 값의 두배로 줌

#define DFT_DUTY 18750 // 초당 주파수 값


int main(void)

...

while(1)

{

for(uiCnt = 0; 100000 > uiCnt; ++uiCnt); // 그냥 딜레이 걸어줌

PWM3_Duty(uiDuty); // 값을 넣어주면

// 1초씩 번갈아 가며 깜빡인다.

}

...


void PWM3_Init(void)

...

*AT91C_PWMC_MR = (0x09 << 8) | // PREA = MCK/512

(5 << 0); // DIVA = 5

// 48 Mhz / 512 = 93750 hz

// 93750 hz / 5 = 18750 hz

...


결과







설정

트랙백

댓글