C++ Chapter 19.8 : 자료형 추론 auto와 decltype

Date:     Updated:

카테고리:

태그:

인프런에 있는 홍정모 교수님의 홍정모의 따라 하며 배우는 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나 &을 붙여줘야 함
  • volatile
    • volatile int vx = 1024;
      • volatile은 값이 자주 변하므로 최적화시엔 빼주어야 하며 멀티스레딩에 자주 쓰인다.
    • auto avx = vx;
      • 역시 volatile을 떼고 int만 들어가서 avx는 int형이 된다.
    • volatile auto vavx = vx;
      • auto가 volatile을 읽게 하고 싶다면 역시 auto 앞에 volatile을 붙여줘야함


예제 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)
      • T& t 에서 crx를 받을때 const int & 가 아닌 int & 까지만 받는다. const는 떼지고 &만 붙여서 처리 됨 ! const int & 까지 다 받는다. (21.07.22 수정)
    • ex3_func3(crx);
      • ex3_func3(const T& t)
      • const T & t 에서 crx를 받을때 const int & 까지 다 받는다.


예제 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를 읽는다.
      • rcconst인 c의 값을 바꾸면 안되기 때문에 auto & 로 받는 경우에는 const를 읽는다.
      • 따라서 rc의 타입은 cosnt int & 가 된다.
        • rc = 123 ; 을 막음. c값이 바뀌면 안되기 때문에.


예제 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를 사용할 수 있다!
}
  • 다른 일반 함수들에서는 파라미터에 auto를 못쓰지만
  • 람다 함수에서는 파라미터에 auto를 쓸 수 있다.
    • auto func = {return x + y; };


🔔 decltype

컴파일 타임에 auto가 타입을 추론하기에 역부족일 때 주로 사용한다.

  • 새로운 데이터 타입을 정의하는 역할을 한다.
    • typedef 사용하는 방법 👉 typedef decltype(A) B
      • A 의 데이터 타입을 B 라는 이름으로 정의한다.
    • typedef 쓰지 않아도 괜찮다. 👉 decltype(A) B = A;
      • A 의 데이터 타입을 B 라는 이름으로 정의한다.
  • autoconst, & 등등은 못 읽는 반면에 decltype은 그대로 다 보존한다.
    • 심지어 decltype(vec[0]) B 에서 vec[0] 대괄호 연산자는 내부적으로 레퍼런스를 리턴 하는데 이를 그대로 보존하여 B 타입을 int & 로 정의한다.
  • 리턴 타입에도 사용 가능하다. 다만 함수 이름 뒤에 -> 리턴 타입 이런 식으로만 가능하다.
  • 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가 이를 추론하기가 명확하지가 않다.
    • 방법 2️⃣
      • typedef decltype(lvar * rvar) product_type;
        • product_type 이라는 데이터 타입을 (lvar * rvar)의 연산 결과의 타입으로 추론되는 타입(decltype)으로 정의(typedef).
        • product_type prod2 = lvar * rvar;
          • prod2의 타입은 product_type 이다.
    • 방법 3️⃣
      • decltype(lvar * rvar) prod3 = lvar * rvar;
        • 그냥 바로 이렇게 정의도 가능.
        • 각각 타입이 (lvar * rvar) 연산 결과를 컴파일러 단계에서 decltype 추론한 후 이를 prod3의 타입으로 정의.


예제 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구조체 타입로 받는다.
  • typedef decltype(foo()) foo_type
    • decltype이기 때문에 foo_type라는 이름의 타입은 const 까지 그대로 물려받아 const S 구조체 타입이 된다.
  • auto b = foobar();
    • auto이기 때문에 b타입은 const & 가 날아가고 그냥 int 타입으로 받는다.
  • typedef decltype(foobar()) foobar_type;
    • decltype이기 때문에 foobar_type라는 이름의 타입은 const & 까지 그대로 물려받아 const int & 타입이 된다.
  • 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이다.
      • 비교한 두 변수가 다른 타입이면 &가 붙지 않는다.
  • 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) &가 붙을 것이기 때문이다. (위 예제 참고)
        • 이땐 리턴 타입이 본연치않게 레퍼런스 타입이 될것이다.
  • 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 & 이다.
  • 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 이다.


예제 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이라고 부르겠다.
  • result_type operator()
    • result_type이 리턴타입인 () 연산자 오버로딩.
  • SomeFunctor<int> func
    • SomeFuctor타입의 func 객체
    • SomeFunctor 클래스의 R 에 int가 들어온다.
  • typedef decltype(func)::result_type integer;
    • decltype(func)
      • func 객체가 들어갔다.
      • func 객체는 SomeFunctor<int> 타입이다.
    • ::result_type
      • SomeFunctor<int> 의 result_type 이니까
      • int가 된다.
    • typedef int integer 이나 마찬가지가 된다.
      • integer는 이제 int의 또다른 이름이 된다.
  • 이런 식으로 클래스 안에 있는 타입에도 접근할 수 있다.


예제 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를 참조함 )


🌜 개인 공부 기록용 블로그입니다. 오류나 틀
린 부분이 있을 경우 
언제든지 댓글 혹은 메일로 지적해주시면 감사하겠습니다! 😄

맨 위로 이동하기

Cpp 카테고리 내 다른 글 보러가기

댓글 남기기