이 글에서는 C++ STL에서 제공하는 std::is_pointer 템플릿의 동작 원리, 사용 문법, 그리고 실전 예제까지 자세히 살펴보겠습니다.
is_pointer는 <type_traits> 헤더 파일에 포함된 템플릿으로, 컴파일 시점에 주어진 타입 T가 포인터 타입인지 아닌지를 판별하는 데 사용됩니다.
포인터란 무엇인가?
포인터(Pointer)는 다른 타입의 메모리 주소를 저장하는 비정적(non-static) 타입입니다. 즉, 메모리 공간상의 특정 위치를 가리키는 역할을 합니다. C++에서는 별표(*) 기호를 사용해 포인터를 선언하며, 포인터가 가리키는 실제 메모리 위치에 접근할 때(역참조)에도 별표(*)를 사용합니다.
포인터는 null 값으로 초기화할 수 있으며, 이후 필요에 따라 가리키는 대상을 얼마든지 변경할 수 있다는 유연성을 갖추고 있습니다.
문법(Syntax)
template <class T> struct is_pointer;
매개변수
이 템플릿은 타입 매개변수 T 하나만 받으며, 해당 타입이 포인터인지 여부를 검사합니다.
반환 값
불리언(Boolean) 값을 반환합니다.
- 주어진 타입이 포인터 타입이면 true
- 포인터 타입이 아니면 false
기본 예제
Input: is_pointer<int>::value; Output: false Input: is_pointer<int*>::value; Output: true
예제 1: 클래스 타입 검사
#include <iostream>
#include <type_traits>
using namespace std;
class TP {
};
int main() {
cout << boolalpha;
cout << "checking for is_pointer:";
cout << "\nTP: " << is_pointer<TP>::value;
cout << "\nTP*: " << is_pointer<TP*>::value;
cout << "\nTP&: " << is_pointer<TP&>::value;
cout << "\nNull Pointer: " << is_pointer<nullptr_t>::value;
return 0;
}실행 결과
위 코드를 실행하면 다음과 같은 출력 결과를 확인할 수 있습니다.
checking for is_pointer: TP: false TP*: true TP&: false Null Pointer: false
위 결과에서 알 수 있듯이, 일반 클래스 타입 TP나 참조 타입 TP&는 포인터로 판별되지 않지만, TP*는 true를 반환합니다. 또한 nullptr_t(널 포인터 리터럴 타입) 역시 포인터 타입으로 간주되지 않는다는 점에 유의하세요.
예제 2: 다중 포인터 검사
#include <iostream>
#include <type_traits>
using namespace std;
int main() {
cout << boolalpha;
cout << "checking for is_pointer:";
cout << "\nint: " << is_pointer<int>::value;
cout << "\nint*: " << is_pointer<int*>::value;
cout << "\nint**: " << is_pointer<int**>::value;
cout << "\nint***: " << is_pointer<int***>::value;
return 0;
}실행 결과
checking for is_pointer: int: false int*: true int**: true int***: true
이 예제를 통해 이중 포인터(int**), 삼중 포인터(int***)처럼 몇 단계로 중첩된 포인터라 하더라도 모두 포인터 타입으로 인식된다는 것을 확인할 수 있습니다.
마무리
std::is_pointer는 템플릿 메타프로그래밍에서 타입에 따라 분기 처리를 해야 할 때 매우 유용한 도구입니다. ::value 멤버를 통해 컴파일 시점에 불리언 상수를 얻을 수 있으며, C++17부터는 is_pointer_v<T> 변수 템플릿 형태로 더 간결하게 사용할 수도 있습니다.