auto
선언한 변수나 람다식의 타입을 컴파일러에게 자료형을 추론하도록 맡김, 실제 자료형은 컴파일 하는 동안 결정된다.
또한 일반 타입 (int, char, string 등) 초기화 하지 않은 변수를 허용하지만 auto는 초기화 하지않고서 사용 불가
포인터를 받을 때 : auto / auto *
참조를 받을 때 : auto&
auto a = 10;
auto &b = a;
a = 5;
cout << b << endl; // 5
범위기반 for문
std::map<int,std::string> m;
m[1] = "abc";
m[2] = "def";
m[3] = "ghi";
// std::map<int,std::string>::iterator it;
for(auto it = m.begin(); it != m.end(); it++)
std::cout << it->first << " " << it->second << std::endl;
template
함수나 클래스를 개별적으로 다시 작성하지 않아도, 여러 자료 형으로 사용할 수 있도록 하게 만들어 놓은 틀
typename
템플릿 정의에서 알 수 없는 식별자가 형식이라는 힌트를 컴파일러에 제공합니다. 템플릿 매개 변수 목록에서 형식 매개 변수를 지정하는 데 사용
예제1) 여러가지 타입
template <typename T>
T Plus(T a, T b) // 같은 T타입끼리만 더한다
{
return a + b;
}
template <> // char* 형에 대해서 특수화
char* Plus(char* a, char* b)
{
size_t a_size = strlen(a);
size_t b_size = strlen(b);
char *str = new char(a_size + b_size + 1);
size_t index = 0;
for(size_t i=0; i<a_size; i++, index++)
str[index] = a[i];
for(size_t i=0; i<a_size; i++, index++)
str[index] = b[i];
str[index++] ='\0';
return str;
}
char* Plus(char* a, char* b) // 일반함수
{
size_t a_size = strlen(a);
size_t b_size = strlen(b);
char *str = new char(a_size + b_size + 1);
size_t index = 0;
for(size_t i=0; i<a_size; i++, index++)
str[index] = a[i];
for(size_t i=0; i<a_size; i++, index++)
str[index] = b[i];
str[index++] ='\0';
return str;
}
int main() {
auto a = Plus(4, 2);
cout << a << endl; // 6 (int)
auto b = Plus(3.0, 1.0);
cout << b << endl; // 4 (double)
string str1 = "abc";
string str2 = "DEF";
auto d = Plus(str1, str2);
cout << d << endl; // abeDEF (string)
auto e = Plus('0', '1'); // char + char 은 ascii값
cout << e << endl; // 48 + 49 = 97 = a
auto f = Plus<char*>("abc", "DEF"); // string이 아니라 char[]로 들어가진다
cout << f << endl; // abcDEF (char*)
delete f;
char ch1[] = "abc";
char ch2[] = "DEF";
auto g = Plus(ch1, ch2); // 일반함수 Plus
cout << g << endl;
char ch3[] = "abc";
char ch4[] = "DEF";
auto f = Plus<char *>(ch3, ch4); // 템플릿 함수 Plus (char *재정의)
cout << f << endl;
// Plus<char *> 처럼 템플릿을 명시하면 템플릿 함수를 호출하고
// Plus 처럼 템플릿을 생략하여 사용하면 일반함수를 호출한다.
// 우선순위 일반함수 > 템플릿 함수
}
int + int , double + double , string + string 같은 인자끼리 서로 더하는 함수를 정의할때 template을 이용하면 자료형마다 함수를 중복으로 작성하지 않아도된다.
또한 정의되지않은 char* + char* 이 매개변수로 들어올경우 특정 매개변수 타입으로 재정의 할수도있다. 이걸 템플릿 명시적 특수화(template explicit specialization) 라고 한다
컴파일 순서
- 템플릿으로 만들어진 함수 템플릿 Plus가 있지만, 컴파일 시 Plus의 자료형을 알지 못하기때문에 그냥 지나친다
- Plus 함수를 호출하는 시점에서 일단 일반함수가 있는지 찾는다 (int, double, string, char는 구현되어있는 일반함수가 없을것이고 char* + char*일 경우에 일반함수 char* Plus(char* , char*)로 들어간다)
- 일반함수에서 찾지 못하였으면 함수 템플릿 Plus를 (int + int일 경우) int형 Plus템플릿 함수로 따로 만들어 준다.
- 만약 다른 자료형이 또 나온다면 같은 방식으로 자료형만 다른 템플릿 함수를 또 만들어준다 (double + double / string + string/ char + char)
-> 겉으로 보기에는 하나의 템플릿 함수를 범용적으로 사용하는 것 처럼 보이지만 내부적 구조를 보면 사용하는 자료형에따라 함수 오버로딩을 사용하는것과 별 차이가없다.
예제2) 여러가지 STL
template <typename T>
void PrintFront(T &v)
{
// T top_element = v.front(); // 에러난다
// 왜냐하면 STL 컨테이너들은 value_type을 가지고있고
// 명확한 상황이 아닌 임의의 타입T를 받아야 할 경우에 쓰라고 있다고한다
// typename T::value_type top_element = v.front();
// 그리고 auto가 생긴 이후부터 이렇게 어렵게 쓰지않아도 컴파일러가
// 타입을 알아서 추론해준다.
auto top_element = v.front();
cout << top_element << endl;
}
int main()
{
vector<int> v{1,2,3};
string str = "123";
queue<int> q; q.push(1); q.push(2); q.push(3);
PrintFront(v);
PrintFront(str);
PrintFront(q);
// map<string, int> m; m["abc"] = 1;
// PrintFront(m);// 해당 STL에 front함수가 없으면 컴파일 실패
}
장점 | 단점 |
컴파일러가 컴파일 도중에 각 템플릿 인스턴스에 대한 코드를 만들어준다 (컴파일 속도는 느리지만 런타임 속도는 더 빠를수 있다)
|
컴파일 타임은 비교적 느리고 템플릿 매개변수를 추가할 수록 더 느려진다
|
'프로그래밍 > C++' 카테고리의 다른 글
캐스팅 (static_cast / dynamic_cast) (0) | 2022.05.12 |
---|---|
Call by value, Call by address, Call by reference / 값에 의한 호출, 주소에 의한 호출, 참조에 의한 호출 (0) | 2022.05.11 |
표준 템플릿 라이브러리(STL) - vector 메모리/ iterator , 표준 라이브러리 - string (0) | 2022.05.03 |
header / namespace (1) | 2022.05.02 |
this 포인터, 연산자 오버로딩 (0) | 2022.04.15 |