is_pointer 라는 클래스는 어떻게 작동하나요?

dltkddyd의 이미지

is_pointer라는 템플릿 클래스의 정의가 다음과 같던데요.

 template<typename _Tp>
    struct is_pointer
    : public integral_constant<bool, (__is_pointer_helper<typename
				      remove_cv<_Tp>::type>::value)>
    { };

상속되는 integral_constant 클래스에서 두 번째 인수는 비타입인수인 것으로 보입니다. 저 value라는 것이 넘어가는 것으로 봐서는요. 그런데 _Tp라는 타입을 보고 __is_pointer_helper라는 클래스에 어떻게 value라는 것이 설정될 수 있나요? 값도 넘겨야 value가 설정될 수 있을 텐데. 잘 이해가 가지 않습니다. 저 __is_pointer_helper라는 클래스의 내부구조를 알 수 있으면 좋을텐데, 알 수가 없네요. 그 이유와 내부구조가 궁금합니다.

mirheekl의 이미지

http://en.cppreference.com/w/cpp/types/is_pointer

이 문서에 의하면 굉장히 간단하네요.

template< class T > struct is_pointer_helper     : std::false_type {};
template< class T > struct is_pointer_helper<T*> : std::true_type {};
template< class T > struct is_pointer : is_pointer_helper<typename std::remove_cv<T>::type> {};

std::false_type이랑 true_type은 아마도 그 인테그럴 상수겠지요. 각각 true랑 false일테고..

is_pointer_helper는 두개가 정의되어 있는데, 위의 것은 포인터형이 아니면 false값으로 대체되고, 아래것은 포인터형일 경우 true로 대체됩니다.
세번째줄은 remove_cv를 통해 각종 CV 키워드들(volatile이라든지 const 등등등..)을 제거하고 그 타입을 is_pointer_help에게 먹이는 역할을 하네요.

본문과 제가 인용한 구현법이 서로 달라보이지만 근본적으로는 같은 것입니다. 말하자면 타입이 정해지는 순간 __is_pointer_helper의 리턴값도 그냥 딱 컴파일 타임에 정해지게 됩니다. 그렇기에 따로 값을 넘겨주지 않아도 true나 false가 나올 수 있는 것.

tunecolor님 덕분에 저도 재밌는 것을 많이 알아가게 되네요!

--

dltkddyd의 이미지

그러니까 하나는 일반 클래스 템플릿이고 다른 하나는 클래스 템플릿의 특수화 형태로 해서 값을 만든다는 말씀이시죠? 그런데 저는 언급하신 타입인수 class T에서 이해가 잘 안됩니다. 예컨대 이런 것이죠. 아래 코드로 질문 드리겠습니다.

#include <iostream>
using namespace std;
 
template<typename ctarg>
class WhatType {
public:
  WhatType() {
    cout<<"포인터가 아닌가?"<<endl;
  }
};
 
template<typename ctarg>
class WhatType<ctarg*> {
public:
  WhatType() {
    cout<<"포인터인가보네?"<<endl;
  }
};
 
int main() {
  WhatType<int> value1;
  WhatType<int*> value2;
 
  return 0;
}

위와 같은 코드가 있는데, main함수 안에서

WhatType나 WhatType이나 모두 template<typename ctarg>에서 ctarg로 받게되면, ctarg 자체가 전자의 경우에는 int이고 후자의 경우에는 int* 가 될 것이고 결국은 두 개의 양식이 서로 충돌되지 않을까요? 그런데 말씀대로 에러는 안 나고 WhatType에서는 앞의 클래스가, WhatType에서는 뒤의 클래스로 value1, value2 객체가 만들어집니다. 포인터의 특수화라는 것이 어떻게 가능한 건가요? 너무 불필요한 질문을 올리는 것인지 모르겠습니다. 그런데 제 머리로는 도대체 이해가 안돼서요.

본인 맞습니다.
인증샷
우헤헤헤... 로 대신합니다.

dltkddyd의 이미지

컴파일러는 컴파일시 특수화된 템플릿의 인수에서 *가 있는 것을 우선적으로 검토한다는 것으로 이해해보도록 하겠습니다.

본인 맞습니다.
인증샷
우헤헤헤... 로 대신합니다.

mirheekl의 이미지

말씀하신 특수화를 사용하되 부분 특수화를 사용한 것입니다.

template< class T > struct is_pointer_helper     : std::false_type {};
template< class T > struct is_pointer_helper<T*> : std::true_type {};

두번째 라인이 부분 특수화이기 때문에 첫번째 라인 없이는 컴파일조차 되지 않습니다. 포인터 타입일때만 후자가 동작하게 되어 있는 것이죠. 그게 부분 특수화의 역할입니다.
반면 두번째 라인을 지워버리면 항상 false값을 얻게 되겠지요. 또하나 예로..

template<> struct is_pointer_helper<int> : std::true_type {}; 

이딴걸 중간에 집어넣으면 int형일때도 true값을 얻게 될것입니다. 전체 특수화지요. 근데 이 방법을 T의 포인터형에 쓰면.. 그냥 위에 것이 동작해버리므로 제대로 구현을 할 수 없게 됩니다. 위에 써주신 의문대로지요!

--

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.