Modern C++ - decltype) 복습을 위해 작성하는 글 2023-11-16

rizz·2023년 11월 16일
0

Modern C++

목록 보기
2/3

📒 C++ - decltype

📌 decltype란?

- 표현식의 타입을 컴파일 시간에 추론할 수 있다.

- 주로 auto와 함께 사용된다.

// C++
#include <iostream>

int main()
{
	decltype(1) num0 = 10; // int
	decltype(num0) num1 = 20; // int
	decltype(num1)& num2 = num1; // int&

	const decltype(num0) num3 = 10; // const int
	const decltype(num0)& num4 = num2; // const int&

	decltype((num0)) num5 = num0; // int&
	decltype(1 + 22.f) num6 = 1.f; // 1 + 22.f를 계산해서 나온 값의 자료형

	int nums0[] = { 1,2,3 };
	decltype(nums0) nums1 = { 1,2,3 }; // int[3]
}

- 위 예제는 decltype의 동작을 확인하기 위해 간단한 표현식을 사용하였지만, 실제에서는 타입이 변경될 가능성이 있을 때 사용하면 유용할 수 있다.

 

📌 decltype과 함수

// C++
#include <iostream>

using std::cout;
using std::endl;

int func(float)
{
	cout << "func : ";
	return 10;
}

int f(float)
{
	cout << "f : ";
	return 20;
}

int i = 0;
int& func0()
{
	cout << "func0 : ";
	return i;
}

struct Person
{
	float weight;
	float height;
};

int main()
{
	// f라는 이름의 함수만 선언이 된 것. f라는 함수를 따로 정의해야 함.
	decltype(func) f; // 함수 선언
	cout << "f : " << f(10.f) << endl;

	decltype(func)& f0 = func; // 함수 레퍼런스
	cout << "f0 : " << f0(10.f) << endl;

	decltype(func)* f1 = func; // 함수 포인터
	cout << "f1 : " << f1(10.f) << endl;

	// func의 반환값으로 선언됨. func가 실행되는 것은 아님.
	decltype(func(1.f)) num7 = 20; // int
	decltype(func0()) num8 = num7; // int&

	// decltype은 컴파일 시간에 추론되기 때문에 굳이 인스턴스를 만들지 않아도 된다.
	decltype(Person::weight) weight1; // float
}

Output:
f : f : 20
f0 : func : 10
f1 : func : 10

- 함수형 포인터 또는 레퍼런스로 형식 지정이 가능하다.

- 함수의 반환 값으로도 형식 지정이 가능하다.

 

// C++
#include <iostream>

struct Wrapper0
{
	int value;

	int getValue() const
	{
		return value;
	}
};

struct Wrapper1
{
	float value;

	// &로 반환하면 외부에서 수정이 될 가능성이 있기 때문에 const는 작성할 수 없다.
	float& getValue()
	{
		return value;
	}
};

template<typename T>
auto getValue(T& t)
{
	return t.getValue();
}

int main()
{
	Wrapper0 w0{ 0 };
	Wrapper1 w1{ 1 };

	getValue(w0);
	getValue(w1) = 20.f; // 에러
}

- 레퍼런스를 auto로 추론 시, 값으로 받아들이기 때문에 수정이 불가하다.

// C++
#include <iostream>

struct Wrapper0
{
	int value;

	int getValue() const
	{
		return value;
	}
};

struct Wrapper1
{
	float value;

	// &로 반환하면 외부에서 수정이 될 가능성이 있기 때문에 const는 작성할 수 없다.
	float& getValue()
	{
		return value;
	}
};

template<typename T>
auto getValue(T& t) -> decltype(t.getValue()) // t.getValue()의 반환 타입으로 리턴
{
	return t.getValue();
}

int main()
{
	Wrapper0 w0{ 0 };
	Wrapper1 w1{ 1 };

	getValue(w0);
	getValue(w1) = 20.f; // 반환 값을 유동적으로 했기 때문에 레퍼런스 타입으로 넘어온다.

	std::cout << getValue(w0) << std::endl; // 값으로 리턴
	std::cout << getValue(w1) << std::endl; // 레퍼런스로 리턴
}

Output:
0
20

- decltype은 레퍼런스도 추론 가능하기 때문에 레퍼런스를 리턴할 수 있게 된다.

- -> decltype(auto)를 사용해도 무방하다.

profile
복습하기 위해 쓰는 글

0개의 댓글