템플릿에서 Non-Type 인자 받기 (Non-Type Template Parameter)

 


 



Non-Type Template Parameter란?

 

Non-Type Template Parameter(NTTP)는 템플릿에서 타입이 아닌 값을 매개변수로 받는 기능이다. 

 

C++20 이전에는 정수형, 포인터, 열거형 등 제한된 타입만 사용할 수 있었지만, 

C++20부터는 구조적 타입(structural type)도 사용할 수 있게 되었다.


 

 

기존의 템플릿에서 Non-Type 사용  (C++20 이전)

 

Non-Type 

  • int, enum
  • 포인터, 참조
  • nullptr_t
// typename 대신에 Non-Type이 들어갈 수 있다.
template<typename T>

 

예시코드

template<double d>
auto GetDouble()
{
	return d;
}

int main()
{
	auto d1 = GetDouble<5.5>();
    
    // 아래의 두 개는 같지만 밑에 것은 바운더리를 벗어났을 경우 체크해 잡아줄 수 있다.
    int arr[5];
    std::array<int, 5> arr;	// int는 런타임 파라미터
}

 

struct ClassType
{
 	// 리터럴 타입(literal type) 만들기
	// 컴파일 타임에 확정, 만약에 constexpr를 떼면 아래의 GetClassType<ClassType(2021)>()부분에서 컴파일되지 않는다.
	constexpr ClassType(int) { }
};

template<int N>
struct IntToType
{
	enum { value = N };
};

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

int main()
{
	auto c1 = GetClassType<ClassType(2021)>();
}

 

 

템플릿에서 Non-Type 인자 받기 (C++20)

 

구조적 타입(structural type) 인자 받기

#include <iostream>
using namespace std;
#include <array>

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

	char _data[N];
};

template<StringLiteral str> // Non-Type인자 StringLiteral를 받아준다.
class ClassTemplate { };

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

int main()
{
	ClassTemplate<"Hello World"> cls1;
	FunctionTemplate<"Hello World">();
}

 


 

 

 

주의사항: std::string은 Non-Type Template Parameter로 사용이 불가능하다!

 

 std::string은 런타임에 동적으로 할당되는 리소스를 관리하므로 Non-Type Template Parameter로 사용할 수 없다. 

대신, 컴파일 타임에 고정된 문자열을 표현하는 구조적 타입을 만들어 사용할 수 있다.

 

template<std::size_t N>
struct FixedString 
{
    char value[N];

    constexpr FixedString(const char (&str)[N]) 
    {
        for (std::size_t i = 0; i < N; ++i)
        {
            value[i] = str[i];
        }
    }
};

template<FixedString fs>
void print_fixed_string() 
{
    std::cout << fs.value << '\n';
}

int main() 
{
    print_fixed_string<FixedString("Hello, World!")>();
}

 

 

왜 Non-Type Template Parameter를 사용할까?

 

Compile-Time Regular Expression(정규 표현식)은 런타임에 동작한다. 

  • std::regex 같은건 런타임 동작

 

정규 표현식 패턴컴파일 타임에 안다면, 굳이 런타임까지 갈 필요 없다! (런타임까지 갈 필요가 없는 경우가 생길 수 있다)

컴파일 타임에 해결이 가능하다!


Non-Type Template Parameter(NTTP)의 활용 사례

  • 컴파일 타임에 결정되는 상수 값을 템플릿 인자로 전달할 때
  • 정적 배열의 크기나 반복 횟수 등을 템플릿 인자로 지정할 때
  • 컴파일 타임에 정규 표현식이나 파서를 생성할 때
  • 형식 안전성을 강화하고 코드의 재사용성을 높일 때