C++ Chapter 19.8 : 자료형 추론 auto와 decltype
카테고리: Cpp
태그: Cpp Programming
인프런에 있는 홍정모 교수님의 홍정모의 따라 하며 배우는 C++ 강의를 듣고 정리한 필기입니다. 😀
🌜 [홍정모의 따라 하며 배우는 C++]강의 들으러 가기!
chapter 19. 모던 C++ 필수 요소들
자료형 추론 auto와 decltype
🔔 auto
긴 타입을 간결하게 줄여준다.
const
,&
,volatile
은 읽지 않는다.- 다만 대입된 것이 포인터일 경우
const
,*
까지 다 읽어들인다. auto &
은const
를 읽는다.auto &&
은 R-value로 선언하고 싶다는 의미. 대입 되는 것이 R-value면auto
는 R-value Reference가 되고, L-value면auto
는 L-value Reference가 된다.- 람다 함수는 파라미터에 auto를 사용할 수 있다.
예제 1️⃣ auto 는 긴 타입을 간결하게 줄여준다.
using namespace std;
void ex()
{
vector<int> vect;
// 1️⃣
for (vector<int>::const_iterator cit = vect.begin(); cit != vect.end(); ++cit)
cout << *cit;
// 2️⃣
for (auto itr = vect.begin(); itr != vect.end(); ++itr)
cout << *itr;
// 3️⃣
for (auto itr : vect)
cout << itr;
}
- vector<int>::const_iterator 라는 긴 타입을
auto
하나로 퉁칠 수 있게 되었다. - 1️⃣ → 2️⃣ → 3️⃣ 순으로 점점 더 간략하게 줄일 수 있게 되었다.
예제 2️⃣ auto 는 const &, volatile 같은 추가 지정은 읽지 않는다.
void ex()
{
int x = int(); // x is an int, initialized to 0
auto auto_x = x;
const int& crx = x; // crx is a const int& that refers to x. 다른 건 못 참조하고 고정.
auto auto_crx1 = crs;
const auto& auto_crx2 = crx;
volatile int vx = 1024;
auto avx = vx;
volatile auto vavx = vx;
}
- int
x
= int();x
는 int 고 0 으로 초기화됨
- auto
auto_x
= x;auto_x
는 x 를 대입받아 int 형이 된다.
const &
- const int&
crx
= x;crx
는 x 를 참조하는 const int & 참조형
- auto
auto_crx1
= crx;auto_crx1
은 crx를 대입받아 const int &이 아닌 int형이 된다.- auto 는 대입받아 형을 결정할때 const와 &을 떼버린다! 그냥 int가 됨
- const auto&
auto_crx2
= crx;- auto가 const & 가 되고싶다면 auto에도 const나 &을 붙여줘야 함
- const int&
volatile
- volatile int
vx
= 1024;volatile
은 값이 자주 변하므로 최적화시엔 빼주어야 하며 멀티스레딩에 자주 쓰인다.
- auto
avx
= vx;- 역시 volatile을 떼고 int만 들어가서
avx
는 int형이 된다.
- 역시 volatile을 떼고 int만 들어가서
- volatile auto
vavx
= vx;- auto가 volatile을 읽게 하고 싶다면 역시 auto 앞에 volatile을 붙여줘야함
- volatile int
예제 3️⃣ 덧붙여 Template T 또한 const, &, volatile 같은건 읽지 않는다.
template<typename T>
void ex_func1(T t) { }
template<typename T>
void ex_func2(T& t) { }
template<typename T>
void ex_func3(const T& t) { }
void ex()
{
const int & crx = 123;
ex3_func1(crx);
ex3_func2(crx);
ex3_func3(crx);
}
- const int &
crx
= 123;- ex3_func1(crx);
- ex3_func1(T t)
T t
에서crx
를 받을때 const int & 가 아닌 그냥 int만 T에 들어가게 된다. (예제 2️⃣ 참고)
- ex3_func2(crx);
- ex3_func2(T& t)
const int & 까지 다 받는다. (21.07.22 수정)T& t
에서crx
를 받을때 const int & 가 아닌 int & 까지만 받는다. const는 떼지고&
만 붙여서 처리 됨 !
- ex3_func3(crx);
- ex3_func3(const T& t)
const T & t
에서crx
를 받을때 const int & 까지 다 받는다.
- ex3_func1(crx);
예제 4️⃣ auto & 경우에는 const를 읽는다.
void ex()
{
const int c = 0;
auto& rc = c;
// rc = 123 - error!
}
- const int
c
= 0;c
는 값을 바꿀 수 없는 const 상수다.
- auto &
rc
= c;rc
는 c의 참조 변수- auto는 const와 &을 안 읽는다고 하지만 auto & 이런 경우에는 const를 읽는다.
rc
가 const인 c의 값을 바꾸면 안되기 때문에 auto & 로 받는 경우에는 const를 읽는다.- 따라서
rc
의 타입은 cosnt int & 가 된다.- rc = 123 ; 을 막음.
c
값이 바뀌면 안되기 때문에.
- rc = 123 ; 을 막음.
예제 5️⃣ auto &&
void ex()
{
int i = 40;
auto && ri = i; // ri는 l-value. int& ri 왜냐하면 들어온게 l-value니까
auto && ri2 = 42; // ri2는 r-value. int&& ri2
auto && ri3 = std::move(i); // ri3는 r-value. int && ri3
}
- int
i
= 40; - auto &&
ri_1
= i;- auto &&는 R-value로 선언하고 싶다는'의미'일 뿐, 반드시 R-value로서 받아들이겠다는건 아니다.
ri_1
는 i를 참조하는데 i는 L-value이기 때문에 ri_1의 타입은 int & 즉 L-value Reference가 된다.
- auto &&
ri_2
= 42;ri_2
는 42를 참조하는데 42는 R-value이기 때문에 ri_2의 타입은 int && 즉 R-value Reference가 된다.
- auto &&
ri_3
= std::move(i);ri_3
는 std::move(i)를 참조하는데 std::move(i)는 i가 R-value로 변환되어 ri_3의 타입은 int && 즉 R-value Reference가 된다.
예제 6️⃣ auto 포인터일 경우에는 const, *를 다 읽어들인다.
void ex()
{
int i = 40;
const int* pi = &i;
auto p = pi;
// ex2, ex4와는 달리 이번에는 int가 아니라 const int * 까지 다 가져옴
// 즉, 포인터일 경우에는 auto가 값을 다 가져오는 것을 알 수 있음
}
- int
i
= 40; - const int *
pi
= &i;pi
는 i의 주소를 담고 있는 const int * 포인터다.- const int * 이기 때문에 간접참 조로 pi 가 가리키는 i의 값을 바꾸는 것이 불가능.
- auto
p
= pi;p
는 const int * 다.- pi 의 값이 대입되니
p
도 pi처럼 i의 주소를 담게된다. - auto 는 포인터의 경우 const까지 읽어온다.
- *p = 43 은 불가능하다. p는 const int *니까.
예제 7️⃣ auto 람다 함수는 파라미터에 auto를 사용할 수 있다.
void ex()
{
// generic lambda;
auto func = [](auto x, auto y) {return x + y; };
cout << func(1.1, 5) << " " << func(3.7, 23.1) << '\n';
// 람다 함수는 parameter로 auto를 사용할 수 있다!
}
🔔 decltype
컴파일 타임에 auto가 타입을 추론하기에 역부족일 때 주로 사용한다.
- 새로운 데이터 타입을 정의하는 역할을 한다.
typedef
사용하는 방법 👉 typedef decltype(A) B- A 의 데이터 타입을 B 라는 이름으로 정의한다.
typedef
쓰지 않아도 괜찮다. 👉 decltype(A) B = A;- A 의 데이터 타입을 B 라는 이름으로 정의한다.
auto
는const
,&
등등은 못 읽는 반면에decltype
은 그대로 다 보존한다.- 심지어 decltype(vec[0]) B 에서
vec[0]
대괄호 연산자는 내부적으로 레퍼런스를 리턴 하는데 이를 그대로 보존하여 B 타입을int &
로 정의한다.
- 심지어 decltype(vec[0]) B 에서
- 리턴 타입에도 사용 가능하다. 다만 함수 이름 뒤에
-> 리턴 타입
이런 식으로만 가능하다. decltype((A))
괄호를 두번 쓰면 레퍼런스&
을 타입에 덧붙여 준다.- A가 연산식이라면
decltype(A)
에서 A 의 연산 결과가 변수라면&
을 타입에 덧붙여 준다.decltype(A)
에서 A 의 연산 결과가 R-value라면&
을 타입에 덧붙여 주지 않는다.- A 연산식에 사용된 두 변수가 같은 데이터 타입이라면 결과 데이터 타입에
&
을 타입에 덧붙여 준다. - A 연산식에 사용된 두 변수가 다른 데이터 타입이라면 결과 데이터 타입에
&
을 타입에 덧붙여 주지 않는다.
- 레퍼런스가 자동으로 붙는게 싫다면
std::remove_reference
를 사용해 없앨 수 있다. - 런타임이 아닌 컴파일 타임에 결정 된다.
예제 1️⃣
template<typename T1, typename T2>
void ex_func(T1 lvar, T2 rvar)
{
auto prod1 = lvar * rvar; // 방법 1️⃣
typedef decltype(lvar * rvar) product_type; // not 계산! only 추론!
product_type prod2 = lvar * rvar; // 방법 2️⃣
decltype(lvar * rvar) prod3 = lvar * rvar; // 방법 3️⃣
}
- void ex_func(T1 lvar, T2 rvar)
- lvar와 rvar를 곱해주는 기능을 수행할 것이다.
- 방법 1️⃣
- auto
prod1
= lvar * rvar;prod1
은 어떤 타입이 될 것인가?- 컴파일러가 실행도 전에 이를 추론하기가 명확치 않음.
- 타입 T1, T2는 실행 후에 결정되는 것이므로.
- 즉 auto가 이를 추론하기가 명확하지가 않다.
- 컴파일러가 실행도 전에 이를 추론하기가 명확치 않음.
- auto
- 방법 2️⃣
- typedef decltype(lvar * rvar)
product_type
;product_type
이라는 데이터 타입을 (lvar * rvar)의 연산 결과의 타입으로 추론되는 타입(decltype)으로 정의(typedef).product_type
prod2
= lvar * rvar;- prod2의 타입은
product_type
이다.
- prod2의 타입은
- typedef decltype(lvar * rvar)
- 방법 3️⃣
- decltype(lvar * rvar)
prod3
= lvar * rvar;- 그냥 바로 이렇게 정의도 가능.
- 각각 타입이 (lvar * rvar) 연산 결과를 컴파일러 단계에서 decltype 추론한 후 이를 prod3의 타입으로 정의.
- decltype(lvar * rvar)
예제 2️⃣ decltype은 리턴 타입에도 사용 가능 하다.
template<typename T1, typename T2>
auto ex_func(T1 lvar, T2 rvar) -> decltype(lvar* rvar)
{
return lvar * rvar;
}
- auto ex_func(T1 lvar, T2 rvar) -> decltype(lvar* rvar)
return lvar * rvar
- lvar * rvar 리턴하는 타입을
decltype(lvar * rvar)
로 해준다.- lvar와 rvar가 어떤 타입이 될지 컴파일러 입장에선 모르기 때문에 auto라는 추론하기 역부족이라서 그렇다. 이럴 때는 decltype을 써줘야함.
- decltype(lvar* rvar) ex8_func(T1 lvar, T2 rvar)
- 원래 리턴 타입을 앞에 써주는 것처럼 decltype(lvar* rvar) 을 함수 이름앞에 써준다면
- 컴파일러 입장에선 lvar* rvar는 아직 선언되지 않은 변수라 함수 이름 앞에 써주면 안된다.
- 함수 이름 뒤에
->
뒤에 리턴 타입을 명시해주자.
예제 3️⃣ decltype(( ))
struct S
{
int m_x; // m_x 멤버를 가지고 있고
S()
{
m_x = 42; // 구조체를 생성하면 m_x 값을 42 로 초기화 한다.
}
};
void ex()
{
int x;
const int cx = 42;
const int& crx = x; // crx는 x를 참조하며 const로서 참조하는 대상을 x에서 다른걸로 바꿀 수 없다.
const S* p = new S(); // 구조체 S의 포인터 p는 const로서 가리키는 대상을 new S()에서 다른걸로 바꿀 수 없다.
auto a = x; // int
auto b = cx; // int (const int 가 아님)
auto c = crx; // int (const int & 가 아님)
auto d = p; // const S * (포인터라 그대로 다 따라 온다.)
auto e = p->m_x; // int (p는 const 포인터이기 때문에 간접참조로 구조체 멤버의 값을 바꿀 수 없고 p->m.x 이렇게 읽을 수만 있다.)
typedef decltype(x) x_type; // int
typedef decltype(cx) cx_type; // const int
typedef decltype(crx) crx_type; // const int &
typedef decltype(p->m_x) m_x_type; // int
typedef decltype((x)) cx_type; // int &
typedef decltype((cx)) cx_with_parens_type; // const int &
typedef decltype((crx)) crx_with_parens_type; // const int & (원래 레퍼런스였다면 그대로 & 유지함)
typedef decltype((p->m_x)) m_x_with_parens_type; // const int & (p는 const이기 때문에 간접참조로 멤버의 값을 바꾸면 안되기 때문에 & 레퍼런스가 되니 값을 바꾸면 안된다는 const까지 따라왔다.)
}
decltype
는 변수가 선언이 된 타입을 그대로 가져온다.const
와&
까지.
decltype((N))
👉 괄호가 두개면 레퍼런스(&)를 추가로 붙여준다.
- typedef decltype((x))
cx_typee
;- &을 추가로 붙여서 int &
- typedef decltype((cx))
cx_with_parens_type
;- &을 추가로 붙여서 const int &
- typedef decltype((crx))
crx_with_parens_type
;- const int &
- 원래 &가 있는 상태면 그대로 & 유지함.
- typedef decltype((p->m_x))
m_x_with_parens_type
;- &가 추가로 붙는데 그냥 int &가 되는게 아닌 const 까지 따라와서 const int &가 된다.
- p는 const이기 때문에 간접참조로 멤버의 값을 바꾸면 안되기 때문에 & 레퍼런스가 되니 값을 바꾸면 안된다는 const까지 따라 온다.
예제 4️⃣ 리턴 타입을 auto 와 decltype 에 넣을 때.
const S foo() { return S(); } // const 구조체 S() 를 리턴한다.
const int& foobar() { return 123; } // const int & 를 리턴한다.
void ex()
{
vector<int> vec = { 10, 20 };
auto a = foo(); // S
typedef decltype(foo()) foo_type; // const S
auto b = foobar(); // int
typedef decltype(foobar()) foobar_type; // const int &
auto itr = vec.begin(); // std::vector<int>::iterator
typedef decltype(vec.begin()) iterator_type; // std::vector<int>::iterator
auto firstElement = vec[0]; // int
decltype(vec[0]) secondElement = vec[0]; // int &
}
- auto
a
= foo()- auto이기 때문에
a
의 타입은 const가 날아가고 그냥 S구조체 타입로 받는다.
- auto이기 때문에
- typedef decltype(foo())
foo_type
- decltype이기 때문에
foo_type
라는 이름의 타입은 const 까지 그대로 물려받아 const S 구조체 타입이 된다.
- decltype이기 때문에
- auto
b
= foobar();- auto이기 때문에 b타입은 const & 가 날아가고 그냥 int 타입으로 받는다.
- typedef decltype(foobar())
foobar_type
;- decltype이기 때문에
foobar_type
라는 이름의 타입은 const & 까지 그대로 물려받아 const int & 타입이 된다.
- decltype이기 때문에
- auto
itr
= vec.begin();- itr은 iterator 타입
- typedef decltype(vec.begin())
iterator_type
;- iterator_type 라는 이름의 타입은 iterator 타입
- auto
firstElement
= vec[0];- vec[0]은 int인 10이다. int이므로 firstElement 의 타입은 int이다.
- decltype(vec[0])
secondElement
= vec[0];- vec[0]은 int인 10이다.
- 내부적으로 [] 대괄호는 레퍼런스를 리턴한다.
- 그래서 decltype 이면 레퍼런스도 유지가 되서 int &가 된다.
- auto 라면 레퍼런스 &는 날라간다.
예제 5️⃣ L-value, R-value
void ex()
{
int x = 0;
int y = 0;
const int cx = 40;
const int cy = 50;
double d1 = 3.14;
double d2 = 9.8;
typedef decltype(x * y) prod_xy_type; // int
auto a = x * y; // int
typedef decltype(cx * cy) prod_cxcy_type; // int
auto b = cx * cy; // int
typedef decltype(d1 < d2 ? d1 : d2) cond_type; // double &
auto c = d1 < d2 ? d1 : d2; // double
typedef decltype(x < d2 ? x : d2) cond_type_mixed; // double
auto d = x < d2 ? x : d2; // double
}
- typedef decltype(x * y)
prod_xy_type
;- x * y의 결과는 int이므로 prod_xy_type는 int.
- auto
a
= x * y;- x * y의 결과는 int이므로 a는 int.
- typedef decltype(cx * cy)
prod_cxcy_type
;- cx 와 cy는 const int지만 두개를 곱한 cx * cy는 int 타입의 R-Value이다.
- 따라서 그냥 int임
- auto
b
= cx * cy;- cx 와 cy는 const int지만 두개를 곱한 cx * cy는 int 타입의 R-Value이다.
- 따라서 그냥 int임
- typedef decltype(d1 < d2 ? d1 : d2)
cond_type
;- d1 = 3.14 < d2 = 9.8 이므로 true 여서 결과는 d1 이다.
- d1는 L-value여서 &까지 붙여 cond_type 는 double& 타입이 된다.
- 이처럼 decltype은 ( ) 안의 결과가 변수이면 &이 추가로 붙고 ( L-value니까 )
decltype( a * b) 같은 R-value가 결과이면 &이 붙지 않는다.
- 단 비교한 두 변수가 같은 타입의 변수여야 한다.
- 말그대로 타입 그대로 보존하여 정확하게 전달해준다.
- auto
c
= d1 < d2 ? d1 : d2;- decltype과 달리 d1은 int인거니까 R-value인지 L-value인지는 따지지않고 날려버리고 c는 double타입이된다.
- typedef decltype(x < d2 ? x : d2)
cond_type_mixed
;- x는 int , d2는 double. x는 0이고 d2는 9.8이므로 연산 결과는 x다
- 근데 이때는 int&가 아니고 double이다.
- 비교한 두 변수가 다른 타입이면 &가 붙지 않는다.
- x는 int , d2는 double. x는 0이고 d2는 9.8이므로 연산 결과는 x다
- auto
d
= x < d2 ? x : d2;- double이다. x가 double로 promotion 됨.
- int와 double의 비교를 위해선 int인 변수가 double로 형변환 되어야 하므로 x는 형변환이 된 상태.
예제 6️⃣ decltype 레퍼런스 없애기 std::remove_reference
// 두 인수 中 더 작은 값을 리턴해주는 함수 구현
template<typename T1, typename T2> // decltype 특성상 두 인수 T1과 T2의 자료형이 같을 경우 &가 붙는다는 단점이 존재한다.
auto fpmin_wrong(T1 x, T2 y) -> decltype(x < y ? x : y)
{
return x < y ? x : y;
}
template<typename T1, typename T2> // 두 인수가 자료형이 같을 경우 &가 붙는 단점을 없애버린다.
auto fpmin(T1 x, T2 y) -> typename std::remove_reference<decltype(x < y ? x : y)>::type
{
return x < y ? x : y;
}
void ex()
{
int i = 42;
double d = 45.1;
auto a = std::min(static_cast<double>(i), d);
int &j = i;
typedef decltype(fpmin_wrong(d, d)) fpmin_return_type1; // double &
typedef decltype(fpmin_wrong(i, d)) fpmin_return_type2; // double
typedef decltype(fpmin_wrong(j, d)) fpmin_return_type3; // double
typedef decltype(fpmin(d, d)) fpmin_return_type4; // double
}
std::min
은 두 argument의 type이 다르면 연산이 안된다. 따라서 아래에 두 type이 다른 argument 중에서 min을 찾아주는 함수를 직접 구현 해볼 것이다.
- auto fpmin_wrong(T1 x, T2 y) -> decltype(x < y ? x : y)
- 리턴 타입 decltype(x < y ? x : y)
- 이 함수는 잘못된 함수다!
- 만약 x와 y의 타입이 같다면 (T1 == T2)
&
가 붙을 것이기 때문이다. (위 예제 참고)- 이땐 리턴 타입이 본연치않게 레퍼런스 타입이 될것이다.
- 만약 x와 y의 타입이 같다면 (T1 == T2)
- auto fpmin(T1 x, T2 y) -> typename std::remove_reference<decltype(x < y ? x : y)>::type
- remove_reference<decltype(x < y ? x : y)> 👉 레퍼런스가 제거 된 decltype(x < y ? x : y) 타입을 리턴한다.
- 레퍼런스가 제거된 ‘타입’ ::type 임을 명시
- typedef decltype(fpmin_wrong(d, d))
fpmin_return_type1
;- d와 d, 즉 타입이 double로 같기 때문에 fpmin_return_type1의 타입은
&
가 추가로 더 붙어 dobule & 이다.
- d와 d, 즉 타입이 double로 같기 때문에 fpmin_return_type1의 타입은
- typedef decltype(fpmin_wrong(i, d))
fpmin_return_type2
;- i와 d, 즉 타입이 int와 double로 다르기 때문에 fpmin_return_type1의 타입은 그냥 dobule 이다.
- typedef decltype(fpmin_wrong(j, d))
fpmin_return_type3
;- j와 d, 즉 타입이 int & 와 double로 다르기 때문에 fpmin_return_type1의 타입은 그냥 dobule 이다. 하나가 int &인 경우에도 그냥 double 이다.
- typedef decltype(fpmin(d, d))
fpmin_return_type4
;- d와 d, 즉 타입이 double로 같지만
&
가 추가로 더 붙지 않고 그냥 double 이다.
- d와 d, 즉 타입이 double로 같지만
예제 7️⃣ decltype 은 런타임이 아닌 컴파일 타임에 결정 된다.
void ex()
{
vector<int> vec;
typedef decltype(vec[0]) integer; // decltype 에서는 '런타임 실행'하지는 않으므로 문제 X
}
- vec는 현재 사이즈가 0 인 비어있는 벡터 다.
- typedef decltype(vec[0])
integer
;- vec[0]은 원래는 런타임 에러다. vec은 비어 있는 벡터라 현재 원소가 없기 때문에.
- 그러나 decltype 은 실제로는 실행을 시키지는 않기 떄문에 에러가 아니다. 컴파일 타임에 결정 되는 것이라서.
예제 8️⃣ decltype 클래스 템플릿, 클래스 안에 있는 타입 접근
template<typename R>
class SomeFunctor
{
public:
typedef R result_type;
SomeFunctor()
{}
result_type operator() () // () 연산자 오버로딩
{
return R();
}
};
void ex()
{
SomeFunctor<int> func;
typedef decltype(func)::result_type integer; // integer = int
}
- typedef R result_type;
- R이라는 타입을
result_type
이라고 부르겠다.
- R이라는 타입을
- result_type operator()
- result_type이 리턴타입인
()
연산자 오버로딩.
- result_type이 리턴타입인
- SomeFunctor<int> func
- SomeFuctor타입의
func
객체 - SomeFunctor 클래스의
R
에 int가 들어온다.
- SomeFuctor타입의
- typedef decltype(func)::result_type integer;
- decltype(func)
- func 객체가 들어갔다.
- func 객체는
SomeFunctor<int>
타입이다.
- ::result_type
SomeFunctor<int>
의 result_type 이니까- int가 된다.
- 즉 typedef int integer 이나 마찬가지가 된다.
integer
는 이제 int의 또다른 이름이 된다.
- decltype(func)
- 이런 식으로 클래스 안에 있는 타입에도 접근할 수 있다.
예제 9️⃣ decltype 람다 함수의 타입 접근하기
void ex()
{
auto func = []() {return 42; };
decltype(func) func2(func); // func2 = func; copy해서 가져온다.
decltype((func)) func3(func); // &func3 = func; ref해서 가져온다.
cout << "func 주소 = " << &func << "\tfunc 값 = " << func() << '\n';
cout << "func2 주소 = " << &func2 << "\tfunc2 값 = " << func2() << '\n';
cout << "func3 주소 = " << &func3 << "\tfunc3 값 = " << func3() << '\n';
}
func
라는 이름의 람다 함수.- int형인 42를 리턴한다.
- decltype(func)
func2
(func);- func2 라는 이름의 람다 함수 (= 함수포인터 변수라고 생각해보자)
- func2 = func 나 마찬가지. func 기능 복사.
- 타입은 decltype(func)
- 초기화 값은 func 값이다. 즉 람다함수 포인터 값.
- decltype((func))
func3
(func);- func3 라는 이름의 람다 함수 (= 함수포인터 변수라고 생각해보자)
- decltype(( )) 이기에 &func3 = func 나 마찬가지. func 기능을 참조
- 타입은 decltype((func)) = decltype(func) &
- 초기화 값은 func 값이다. 즉 람다함수 포인터 값.
- func 와 func2 는 주소가 다르다. 즉 별개의 람다 함수. ( func로부터 복사 되었을 뿐 )
- func 와 func2 는 주소가 같다. 즉 동일한 주소의 람다 함수. ( func를 참조함 )
🌜 개인 공부 기록용 블로그입니다. 오류나 틀
린 부분이 있을 경우
언제든지 댓글 혹은 메일로 지적해주시면 감사하겠습니다! 😄
댓글 남기기