Notice
Recent Posts
Recent Comments
Link
- 책_곽용재님 홈페이지
- 책_노란북 - 책 가격비교
- 책_김재우-SICP번역
- 플밍_쏘쓰포지
- 플밍_CodingHorror ?
- 플밍_상킴
- 플밍_김민장님
- GPGStudy
- 플밍_미친감자님
- 플밍_jz
- 플밍_샤방샤방님
- 플밍_글쓰는프로그래머2
- 플밍_키보드후킹
- 사람_재혁
- 사람_kernel0
- 사람_박PD
- 사람_경석형
- 사람_nemo
- 사람_kikiwaka
- 사람_Junios
- 사람_harry
- 사람_어떤 개발자의 금서목록..
- 사람_모기소리
- 사람_낙타한마리
- 사람_redkuma
- 사람_영원의끝
- 사람_민식형
- 도스박스 다음카페
- 플레이웨어즈 - 게임하드웨어벤치마크
- http://puwazaza.com/
- David harvey의 Reading Marx's c…
- 씨네21
- 한겨레_임경선의 이기적인 상담실
- 본격2차대전만화 - 굽시니스트
- 영화_정성일 글모음 페이지
- 영화_영화속이데올로기파악하기
- 음식_생선회
- 죽력고
- 사람_한밀
- 플밍_수까락
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
Tags
- 영화
- 책
- 정성일
- 삼국지
- 단상
- 인문학
- c++
- 건강
- 진삼국무쌍5
- 태그가 아깝다
- programming challenges
- 진중권
- 김두식
- 유머
- 고등학교 사회공부
- 강유원
- BSP
- 노무현
- template
- Programming
- 게임
- 유시민
- 정신분석
- 소비자고발
- 삼국지6
- modernc++
- 일리아스
- 프로그래밍
- stl
- 고전강의
Archives
- Today
- Total
01-05 01:43
lancelot.com
type deduction 본문
- type deduction 이란?
- 컴파일러가 주어진 조건(표현식)을 가지고 타입을 결정하는 과정
- type deduction 이 발생하는 경우
- template
- auto
- decltype
- auto 와 template 은 동일한 규칙을 사용
int main()
{
int n = 10;
const int c = 10;
auto a1 = n; // int a1=n;
auto a2 = c; // (1) const int a2=c;
// (2) int a2=c; ==> ok
}
- 추론된 타입을 조사하는 방법
- typeid(T).name()
- g++ : 실행파일 이름 | c++filt -t
- const / volatile / reference 정보가 출력되지 않는다.
- error 메세지 확인
- 의도적으로 에러를 발생시키면 에러 메세지 안에서 타입 확인 가능
- "boost::type_index" 라이브러리 사용
- type_id_with_cvr<T>().pretty_name()
- boost를 설치해야 한다.
- 컴파일러가 제공하는 "함수이름을 담은 매크로"
- __FUNCTION__ : C++ 표준. 함수 이름만 나타냄
- __PRETTY_FUNCTION__ : g++, clang++
- __FUNCSIG__ : Visual studio ( cl.exe )
- typeid(T).name()
- Template type deduction 에서의 핵심 사항
- T arg : 인자를 값으로 받을 때
- T& arg : 인자를 lvalue reference 로 받을 때
- T&& arg : 인자를 rvalue reference 로 받을 때
- 인자로 배열이 전달될 때
- 규칙1. template 인자를 값(T arg) 으로 받을 때
- 새로운 복사본 객체가 만들어져 값을 복사 받는 것
- 함수 "인자의 const, volatile, reference를 제거하고 T의 타입을 결정" 한다.
- 주의! 인자의 const 속성만 제거 된다. "인자가 가리키는 곳의 const 속성은 유지"
#include<iostream>
template<typename T>
void foo(T arg)
{
std::cout << __FUNCSIG__ << std::endl;
}
int main()
{
int n = 10;
int& r = n;
const int c = 10;
const int& cr = c;
foo(n); // T=int
foo(r); // T=int
foo(c); // T=int
foo(cr);// T=int
}
- 인자의 const 속성만 제거된다. "인자가 가리키는 곳의 const 속성은 유지"
#include<iostream>
template<typename T>
void foo(T arg)
{
std::cout << __FUNCSIG__ << std::endl;
}
int main()
{
const char* const s = "hello";
foo(s);
}
- 규칙2. Template 인자를 lvalue reference(T& arg) 로 받을때
- T의 타입과 arg의 타입은 다르다
- 함수 인자의 "reference 를 제거하고 T의 타입을 결정"한다.
- 인자가 가진 "const, volatile 속성은 유지"
#include<iostream>
template<typename T>
void foo(T& arg)
{
std::cout << __FUNCSIG__ << std::endl;
}
int main()
{
int n = 10;
int& r = n;
const int c = 10;
const int& cr = c;
foo(n); // T=int arg=int&
foo(c); // T=const int arg=const int&
foo(r); // T=int arg=int&
foo(cr);// T=const int arg=const int&
}
- template 인자에 배열을 전달할 때
- T arg = x
- int arg[3] = x; 이 코드는 컴파일 에러
- int* arg = x; 이 코드는 컴파일 에러 아님
- T& arg = x
- int (&arg)[3]=x; // 배열을 가리키는 참조 컴파일 에러 아님
- T arg = x
#include<iostream>
template<typename T>
void foo(T arg)
{
std::cout << __FUNCSIG__ << std::endl;
}
template<typename T>
void goo(T& arg)
{
std::cout << __FUNCSIG__ << std::endl;
}
int main()
{
int x[3] = { 1,2,3 };
foo(x); // T=int* arg=int*
goo(x); // T=int[3] arg=int(&)[3]
}
- T arg : T는 포인터( int *)
- T& arg
- T는 배열( int[3])
- arg는 배열을 가리키는 참조( int (&)[3] )
- 또다른 예시
#include<iostream>
template<typename T>
void foo(T arg1, T arg2)
{
}
template<typename T>
void goo(T& arg1, T& arg2)
{
}
int main()
{
foo("orange", "apple"); // ok
// foo(const char[7], const char[6])
// 하지만 T 일때는 *로 받음
goo("orange", "apple"); // error
// goo( const char[7], const char[6])
// 배열 갯수가 다르면 타입이 다름
goo("orange", "banana"); // ok
}
- auto type deduction
- template : 함수 인자로 타입 추론 - T arg = 함수인자;
- auto : 우변의 표현식으로 타입 추론 - auto a = 표현식;
- auto 와 배열, int x[3] 일 때,
- auto a=x : auto 는 포인터 ( int* )
- auto& a=x : auto 는 배열 ( int[3] ), a는 배열을 가리키는 포인터( int(&)[3] )
int main()
{
int n = 10;
int& r = n;
const int c = 10;
const int& cr = c;
// 규칙 1
// T arg : 함수 인자의 const, volatile, reference 를 제거하고 T의 타입 결정
auto a1 = n; // auto int
auto a2 = r; // auto int
auto a3 = c; // auto int
auto a4 = cr; // auto int
// 규칙2
// T& arg : 인자의 reference 만 제거하고 T의 타입 결정. const, volatile 은 유지
auto& a5 = n; // auto int a5=int&
auto& a6 = r; // auto int a6=int&
auto& a7 = c; // auto const int a7=const int &
auto& a8 = cr; // auto const int a8o=const int &
int x[3] = { 1,2,3 };
auto a = x; // auto int*
auto& b = x; // auto int[3] b=int(&)[3]
}
- int vs std::initializer_list
#include<iostream>
#include<vector>
int main()
{
auto a1 = 1; // int
auto a2 = { 1 };// std::initializer_list<int>
auto a3{ 1 }; // int
std::cout << typeid(a1).name() << std::endl;
std::cout << typeid(a2).name() << std::endl;
std::cout << typeid(a3).name() << std::endl;
std::vector<int> v1(10, 0);
std::vector<bool> v2(10, false);
auto a4 = v1[0]; // auto=int
auto a5 = v2[0]; // auto= "proxy 객체"
// std::vector<bool>
// -> 최적화를 위해 specialization 되어있음
// -> [] 연산자가 bool 로 변환가능한 "Temporary proxy 를 반환"
std::cout << typeid(a4).name() << std::endl;
std::cout << typeid(a5).name() << std::endl;
}
- std::vector<bool>
- 최적화를 위해 specialization 되어있음
- [] 연산자가 bool 로 변환가능한 "Temporary proxy 를 반환"
- 구현에 따라 다를 수 있음
- decltype type deduction
- decltype(expression)
- ( ) 안에 있는 표현식으로 타입 결정
- 2가지 규칙
- ( ) 안에 있는 표현식이 심볼의 이름만 있는 경우
- ( ) 안에 심볼 외에 연산자 등을 포함함 표현식이 있는 경우
- 규칙1. ( ) 안에 심볼의 이름만 있는 경우
- 심볼의 선언을 통해서 심볼과 동일한 타입으로 결정
- decltype(expression)
#include<iostream>
int main()
{
int n = 10;
int& r = n;
int* p = &n;
const int c = 10;
const int& cr = c;
decltype(n) d1; // int d1
decltype(r) d2; // int& d2 -> 초기화 문제로 error
decltype(p) d3; // int* d3
decltype(c) d4; // const int d4 -> 초기화 문제로 error
decltype(cr) d5;// const int& d5 -> 초기화 문제로 error
}
- (참고) 함수의 반환 타입
- 값 타입으로 반환하는 함수
- 등호의 왼쪽에 올 수 없다.
- lvalue가 될 수 없다.
- 참조 타입으로 반환하는 함수
- 등호의 왼쪽에 올 수 있다.
- lvalue가 될 수 있다.
- 값 타입으로 반환하는 함수
- 규칙 2. ( ) 안에 심볼 이름 외에 연사잔 등을 포함한 표현식이 있는 경우
- 표현식의 결과가 등호의 왼쪽에 올 수 있으면 reference 타입( &, lvalue reference )
- 표현식의 결과가 등호의 왼쪽에 올 수 없으면 값 타입
- 표현식이 move() 와 같이 rvalue reference 를 반환하면 rvalue reference 타입(&&)
int x = 10;
int foo() { return x; }
int& goo() { return x; }
int main()
{
// foo() = 20; // 10 = 20 error
goo() = 20; // x의 별명 = 20 ok
int n = 10;
int* p = &n;
decltype(p) d1; // int* d1;
// decltype(*p) d2; // int& d2; -> *p=30 가능 초기값 문제로 error
decltype(n) d3; // int d3;
decltype(n+1) d4; // int d4; -> n+1=30 불가능
// decltype((n)) d5; // int& d5; -> (n)=30 가능 초기값 문제로 error
// decltype(n=20) d6; // int& d6; -> n=20=30 가능 초기값 문제로 error
int x[3] = { 1,2,3 };
// decltype(x[0]) d7; // int& d7; 초기값 문제로 error
auto a1 = x[0]; // int a1 -> x[0] 가 int& 인데, auto 에서는 &가 제거되므로 auto가 int가 되는 것.
decltype(x) d8; // int d8[3];
auto a2 = x; // int a2[3]=x; 에러이므로
// int* a2=x;
decltype(n++) d9; // int d9; n이 표현식에 참여하고 ++는 나중에 적용
// decltype(++n) d10;// int& d10 ++n 이 표현식이므로 규칙2가 되어서 int& -> &의 초기화가 없어서 error
}
decltype( *p ) | *p = 30 | ok | int& |
decltype( n+1 ) | n+1 = 30 | error | int |
decltype( (n) ) | (n) = 30 | ok | int& |
decltype( n=20 ) | n=20 = 30 | ok | int& |
decltype( x[0] ) | x[0] = 30 | ok | int& |
decltype( x ) | 규칙 1 | int[3] |
- decltype( auto )
- decltype( 함수이름 )
- 함수의 타입
- decltype( 함수호출식 )
- 함수 실행의 결과 타입, 즉, 함수 반환타입
- 실제 함수가 호출되는 것은 아님.
- 함수 구현이 업어도 선언만 있으면 사용가능
- "평가되지 않은 표현식( unevaluated expression )"
- decltype( auto )
- auto 위치에 우변 표현식을 넣어서 타입 추론
- 즉, 우변 표현식으로 타입을 추론하는데, 규칙은 decltype 규칙 사용
- C++14 부터 사용가능
- decltype( 함수이름 )
#include<iostream>
int x = 10;
int foo(int a, int b) { return x; }
int& goo(int a, int b) { return x; }
int main()
{
decltype(foo) d1; // int(int, int)
// int d1(int, int)
decltype(foo(1,2)) d2; // int d2;
// decltype(goo(1, 2)) d3; // int& d3;
auto ret1 = goo(1, 2); // int ret1=goo(1,2);
decltype(goo(1, 2)) ret2 = goo(1, 2);
// int& ret2=goo(1,2);
// 위의 표현이 복잡하니, 아래처럼 auto를 쓸수있다.
decltype(auto) ret3 = goo(1, 2);
ret3 = 1000;
std::cout << x << std::endl;
}
- decltype( auto )
- decltype( a+b ) Add(T1 a, T2 b)
- 컴파일 에러. 선언되지 않은 변수 사용
- auto Add(T1 a, T2 b) -> decltype( a+b )
- 에러 아님. 정확한 타입으로 반환
- auto Add(T1 a, T2 b)
- 에러 아님
- 리턴문의 표현식이 참조라면, 참조를 제거한 타입 반환(auto의 규칙을 따르므로)
- decltype(auto) Add(T1 a, T2 b)
- 정확한 타입으로 반환
- 가장 널리 사용
- C++14부터 가능, C++11이라면 2번째 표기법 사용
- decltype( a+b ) Add(T1 a, T2 b)
#include<iostream>
template<typename T> T Add(T a, T b)
{
return a + b;
}
// template<typename T1, typename T2> decltype(a+b) Add(T1 a, T2 b) error 선언되지 않은 변수 사용
// template<typename T1, typename T2> auto Add(T1 a, T2 b) -> decltype(a+b) // ok 정확한 타입으로 반환
// template<typename T1, typename T2> auto Add(T1 a, T2 b) // ok. 하지만 auto의 규칙을 따르기때문에, return문의 표현식이 참조라면 참조를 제거한 타입을 반환
template<typename T1, typename T2> decltype(auto) Add(T1 a, T2 b) // ok. 정확한 타입으로 반환. 가장 널리사용. C++14부터 가능. C++11이라면 2번째 표기법 사용
{
return a + b;
}
int main()
{
std::cout << Add(1,2) << std::endl;
std::cout << Add(1, 2.3) << std::endl;
}