본문 바로가기
C++20/Language

[C++20 - Language] Chapter 05. Non-Type Template Parameter

by song.ift 2023. 7. 28.

GitHub : https://github.com/developeSHG/CPP20-Language/commit/84f811e96a0a5518f76a242fc3ec07777d3067c7

 

Non-Type Template Parameter · developeSHG/CPP20-Language@84f811e

developeSHG committed Jul 28, 2023

github.com

 

 


 

 

일방적으로 템플릿을 사용할 때,
어떤 타입에 대응해서 치환을 하게끔 설정했는데
경우에 따라서 지정된 타입(int 등)으로도 사용했었다.
그래서 Non-Type에 대해서만 들어갔었는데, C++20로 넘어오면서 추가된 것들이 생겼다.
보다보면 약간 흑마법같은 기능.

// Non-Type
// - int, enum
// - 포인터, 참조값
// - nullptr_t

// C++20 에서 추가된 것
// - 부동소수점 (floating-point)
// - Literal Type (types of constexpr variables)
// - String Literal

 

// 근데 이런걸 왜 씀?
// ex) Compile-Time Regular Expression (정규 표현식)
// 정규 표현식이란 건 어떤 문자열(s*1^sdfsd)의 형태를 만든다면, 그 표현식에 부합하는지 안하는지 이용해서 패턴 매칭을 해주는 것.
// 정규 표현식 계산을 하고 싶을때, 정규 표현식을 std::regex 란 걸 이용해서 만드는데, regex는 런타임에서만 동작한다.
// 정규 표현식 패턴을 미리 컴파일 타임에 안다면, 굳이 런타임까지 갈 필요 없음.

// 그래서 기존 방식을 이용할 수 없었지만, 
// 위에 새로운 문법을 이용해서 클래스를 타입화 한 것처럼
// 최대한 컴파일 타임에 해결할 수 있는 수단이 된다는 게 힌트.
// 그럼에도 거의 잘 사용할 일이 없을듯. (그래서 흑마법이라 한 것)

 

#include <iostream>
using namespace std;
#include <list>
#include <vector>
#include <map>
#include <algorithm>
#include <ranges>
#include <concepts>
#include <coroutine>
#include <array>
// 오늘의 주제 : Non-Type Template Parameter

// 일방적으로 템플릿을 사용할 때,
// 어떤 타입에 대응해서 치환을 하게끔 설정했는데
// 경우에 따라서 지정된 타입(int 등)으로도 사용했었다.
// 그래서 Non-Type에 대해서만 들어갔었는데, C++20로 넘어오면서 추가된 것들이 생겼다.
// 보다보면 약간 흑마법같은 기능.

// Non-Type
// - int, enum
// - 포인터, 참조값
// - nullptr_t

// C++20 에서 추가된 것
// - 부동소수점 (floating-point)
// - Literal Type (types of constexpr variables)
// - String Literal

// int나 enum같은 정수만 지원됐었는데, 부동소수점까지 지원하게 됐다.
template<double d>
auto GetDouble()
{
	return d;
}

// 거의 리터럴 타입.
// constexpr을 이용해서 거의 상수처럼 고정을 해서 만든 것.
// 기존에 사용하던 클래스나 구조체 경우는 객체로 사용하기 위한 설계도였는데,
// 이것은 정수 하나를 일종의 타입으로 만들기위한 꼼수를 이용한 것.
struct ClassType
{
	// constexpr을 넣어줌으로써, 컴파일 타임에 생성자도 확정이 되어 만들어질 수 있다.
	// 그래서 밑에 메인함수에 2021 같은 상수도 들어간 것.
	constexpr ClassType(int) { }
};

// 이것도 정수를 타입처럼 만들기 위해 구조체를 만든 것.
template<int N>
struct IntToType
{
	enum { value = N };
};

template<ClassType c>
auto GetClassType()
{
	return c;
}

template<int N>
class StringLiteral
{
public:
	constexpr StringLiteral(char const (&str)[N])
	{
		std::copy(str, str + N, _data);
	}

	char _data[N];
};

template<StringLiteral str>
class ClassTemplate { };

template<StringLiteral str>
void FunctionTemplate()
{
	cout << str._data << endl;
}

int main()
{
	auto d1 = GetDouble<5.5>();
	auto c1 = GetClassType<ClassType(2021)>(); // 넣어주는 정수에 따라 타입 자체가 완전히 달라진다.

	// 두 개도 정수지만, 완전히 다른 타입인 셈. (마치 개와 고양이)
	IntToType<2>();
	IntToType<3>();

	// 템플릿 문법 안에서는 어떤 클래스 타입만 넣어줬지만, 정수뿐만 아니라 문자열도 넣어줄 수 있다.
	ClassTemplate<"Hello World"> cls1;
	FunctionTemplate<"Hello World">();

	// 근데 이런걸 왜 씀?
	// ex) Compile-Time Regular Expression (정규 표현식)
	// 정규 표현식이란 건 어떤 문자열(s*1^sdfsd)의 형태를 만든다면, 그 표현식에 부합하는지 안하는지 이용해서 패턴 매칭을 해주는 것.
	// 정규 표현식 계산을 하고 싶을때, 정규 표현식을 std::regex 란 걸 이용해서 만드는데, regex는 런타임에서만 동작한다.
	// 정규 표현식 패턴을 미리 컴파일 타임에 안다면, 굳이 런타임까지 갈 필요 없음.
	
	// 그래서 기존 방식을 이용할 수 없었지만, 
	// 위에 새로운 문법을 이용해서 클래스를 타입화 한 것처럼
	// 최대한 컴파일 타임에 해결할 수 있는 수단이 된다는 게 힌트.
	// 그럼에도 거의 잘 사용할 일이 없을듯. (그래서 흑마법이라 한 것)
}

 

 

댓글