C++ 멤버템플릿의 특수화에 관한 마법같은(?) 코드

oosap의 이미지

C++ 멤버템플릿의 특수화에 관한 VS 와 g++ 의 상이한 내용에 대해 찾아보던 중 stack overflow 에서 한 쓰레드를 찾았습니다.

http://stackoverflow.com/questions/3052579/explicit-specialization-in-non-namespace-scope

VS 에서는 g++ 이 지원하지 않는 문법이 아마도 컴파일러 확장문법으로 지원이 되는 것 같습니다. 이로 인해 g++ 과 호환성 문제가 발생을 하고요, 이 문제의 해결책으로 g++ 에서는 다음과 같이 VS 의 확장문법으로 작성된 코드를 구현할 수 있습니다.

#include <iostream>
 
template<typename T>
struct identity { typedef T type; };
 
template<typename T>
class CConstraint
{
	public:
		template <typename TL>
		void Verify(int position, int* constraints) {
			Verify(position, constraints, identity<TL>());
		}
 
	private:
		template<typename TL>
		void Verify(int, int*, identity<TL>) {
			std::cout << "111" << std::endl;
		}
 
		void Verify(int, int*, identity<int>) {
			std::cout << "222" << std::endl;
		}
 
		void Verify(int, int*, identity<long>) {
			std::cout << "333" << std::endl;
		}
};
 
int main()
{
	int arg = 100;
 
	CConstraint <char> obj;
	obj.Verify<int>(100, &arg);     //222
	obj.Verify<char>(100, &arg);  //111
	obj.Verify<long>(100, &arg);  //333
 
	CConstraint <long> obj2;      
	obj2.Verify<int>(100, &arg);    //222
	obj2.Verify<char>(100, &arg); //111
	obj2.Verify<long>(100, &arg); //333
 
	return 0;
}

이 코드는 스택오버플로에 소개된 코드를 제가 테스트해본 것인데 우분투에서 g++ 로 컴파일과 실행이 잘 됩니다. 결과는 main 함수의 주석에 표시한 바와 같이 의도한 바가 정확히 동작합니다.

그런데 제가 이 코드를 이해를 못하겠습니다.

template<typename T>
struct identity { typedef T type; };

이 부분의 역할이 제가 이해를 못하는 부분입니다.
typedef T type; 이 어떤 역할을 하는 것이죠? ( 제 질문은 바로 이겁니다. )

동작은 마법같이 잘 되서 기쁘긴 합니다만, 원리를 모르니 답답합니다.
굉장히 멋진 코드처럼만 보입니다. 이해가 안되니 멋있게 보이네요..

oosap의 이미지

http://kldp.org/node/62341

이 쓰레드 내용도 저에게는 난해합니다.

Thanks for being one of those who care for people and mankind.
I'd like to be one of those as well.

oosap의 이미지

#include <iostream>
 
template<typename T>
struct identity { typedef T type; };
 
template<typename T>
class CConstraint
{
	public:
		template <typename TL>
			void Verify(int position, int* constraints);
 
	private:
		template<typename TL>
			void Verify(int, int*, identity<TL>);
		void Verify(int, int*, identity<int>);
		void Verify(int, int*, identity<long>);
};
 
 
template<typename T>
template <typename TL>
void CConstraint<T>::Verify(int position, int* constraints)
{
	Verify(position, constraints, identity<TL>());
}
 
template<typename T>
template<typename TL>
void CConstraint<T>::Verify(int, int*, identity<TL>)
{
	std::cout << "111" << std::endl;
}
 
template<typename T>
void CConstraint<T>::Verify(int, int*, identity<int>)
{
	std::cout << "222" << std::endl;
}
 
template<typename T>
void CConstraint<T>::Verify(int, int*, identity<long>)
{
	std::cout << "333" << std::endl;
}
 
 
int main()
{
	int arg = 100;
 
	CConstraint <char> obj;
	obj.Verify<int>(100, &arg);   //222
	obj.Verify<char>(100, &arg);  //111
	obj.Verify<long>(100, &arg);  //333
 
	CConstraint <long> obj2;      
	obj2.Verify<int>(100, &arg);  //222
	obj2.Verify<char>(100, &arg); //111
	obj2.Verify<long>(100, &arg); //333
 
	return 0;
}

http://stackoverflow.com/questions/3052579/explicit-specialization-in-non-namespace-scope

출처도 다시금 밝힙니다.

Thanks for being one of those who care for people and mankind.
I'd like to be one of those as well.

익명 사용자의 이미지

template<typename T>
struct identity { typedef T type; };

는 C++ 라이브러리에서 매우 흔히 사용되는 방법입니다.

예를 들어서 container에서 원소의 자료형을 저장(?)할 수 있는 방법이죠.
즉 vector::value_type이 int죠.

template <typename T, ...... >
struct vector {
  typedef T value_type;
 ......

뭐 대충 이렇게 되어 있는거죠.

익명 사용자의 이미지

즉 vector<int>::value_type이 int죠.
익명 사용자의 이미지

근데 위 코드에서는
typedef T type; 는 사실 아무런 역할이 없습니다. ^^
아마도 template를 만들때 너무 흔하게 쓰는 표현이라서 아무것도 안적기는 썰렁하여 적어둔거 같네요... ㅋ

그러니까

template<typename T>
struct identity { typedef T type; };

가 아니라

template<typename T>
struct identity { };

라고 해도 아무 문제가 없을거라 생각되는군요.
oosap의 이미지

아! 정말 그렇습니다.
컴파일러가 제한하는 멤버 템플릿의 특수화를 구현하기 위해 더미 템플릿 구조체를 사용한 것이네요.... VS 에서는 이렇게 꽁수를 쓰지 않아도 되도록 확장문법을 제공하고 있는 것이구요..

ㅎㅎ 이제 좀 확인이 되었습니다.

템플릿 정말 복잡하군요..

Thanks for being one of those who care for people and mankind.
I'd like to be one of those as well.

yielding의 이미지

template<typename T>
struct identity 
{ 
  typedef T type 
}

은 meta function입니다.

c++ template로 meta programming이 가능하다는 것이 우연히 발견된 이후 (template로 짠 코드의 에러 메시지가 재귀호출의 출력과 동일한 것을 발견.)
많은 사람들이 c++ template로 meta programming을 연구했고, boost의 David Abrahams과 그 친구들이 이것을 boost::mpl(meta programming library) 로 만들면서 c++ template meta programming의 개념을 나름데로 정리했습니다.

c 언어의 function과 c++의 meta function을 비교하면 형태적으로 비슷합니다.

int identity(int t)
{
  return t;
}
 
template<typename T>
struct identity 
{ 
    typedef T type 
};


C function은 변수를 받고 변수를 리턴하지만, meta function은 인자로 0개 이상의 타입을 받고 type computation의 결과로 type을 리턴(typedef XXXX type)을 하는 거지요.
identity meta function은 받은걸 그대로 리턴해서 하는 것이 없어 보일 수 있지만 다른 meta function과 섞여 복잡한 type computation을 할 때에는 꼭 필요한 함수입니다.

C++ template Metaprogramming concepts, tools, and techniques 1독 권해드립니다.

Life rushes on, we are distracted

oosap의 이미지

C++ 은 해도해도 끝이 없는 것 같습니다.
메타프로그램... 애써 외면하고 있습니다만, 결국 봐야만 하는 걸까요?
피할 수 없으면 즐기라고 KLDP 에서는 (snowall 님이) 수도 없이 이야기 하고 있지만요...

우연히 발견됐다구요? 정말 신기하네요.. 역사적인 것은 우연에 의한다고 어제 저녁에 티비에서 전기뱀장어라는 밴드가 이야기하는 것을 보았는데요... 급 관심이 생깁니다.
동시에 자신감 급 상실이네요.. 겁이 납니다. 이 길을 제가 건너가볼 수 있을지..

Thanks for being one of those who care for people and mankind.
I'd like to be one of those as well.

yielding의 이미지

우연히 발견됬다는 사실이 진짜 신기하죠?

c++로 TMP(Template Meta Programming)하는 것은 많은 공부와 인내(컴파일 타임..)가 필요합니다만, 그 결과물 또한 놀랍죠. boost.Spirit을 보면 TMP가 얼마나 탁월한 DSL을 만들어 낼 수 있는지를 확인할 수 있습니다.
동시에 boost.Spirit이 처음 개발된 후 지금까지 업데이트하고 있는 시간을 보면 또 놀라게 됩니다.

반드시 잘해야되는 것도 아니고, c++하는 사람들이 누구나 TMP를 잘하는 것도 아니니 자신감 상실하지 마시고 snowball님께서 말씀하신 것처럼 즐기시면 될듯합니다.

즐프 하세요~

Life rushes on, we are distracted

oosap의 이미지

좋은 자극을 많이 주셨습니다.

알려주신 책을 잠시 보았으나 제 내공으로는 아직 무리였습니다.
하지만 Modern C++ Design 이라는 책은 볼 수 있더군요. 상대적으로 훨씬 쉽게 읽힙니다. 그리고 그 책에서 이와 관련된 설명을 찾았습니다.

2장 5절 자료형에서 다른 자료형으로의 매핑

입니다. 맴버 함수는 클래스와 달리 부분 특수화 대신 오버로딩을 사용하고 이럴 때 이런 식의 템플릿을 사용합니다. 이 책에서는 메타 함수라는 이름 대신 Type2Type 이라는 템플릿으로 부릅니다.

=================

시간이 몇 개월이 흘렀습니다만 관련 내용을 발견했습니다.

GotW #79

C++ Template Guide, 반데보드 와 조슈티스 에도 13.6 절에 typedef 템플릿 이라는 설명이 들어있습니다. 결국 typedef 을 템플릿으로 사용하고 싶은데 지금까지의 C++ 에서 그것이 구현되어있지 않아서 같은 목적의 최선의 구현을 현재까지의 C++ 기술로 해낸 것입니다.

C++0x 미리보기 3, 템플릿 별칭 (1부)
Type alias (since C++11)

이미 c++11 에서는 이런 필요성이 문법적으로 받아들여졌군요...
자답이지만 문서화 작업으로 생각하며 쓰레드를 이어나가봅니다.

Thanks for being one of those who care for people and mankind.
I'd like to be one of those as well.

oosap의 이미지

답변 감사합니다. 감사하다는 말을 해야겠다고 자려다가 문득 생각이 나더군요..

Thanks for being one of those who care for people and mankind.
I'd like to be one of those as well.

익명 사용자의 이미지

위 방법은 별로 유용할거 같진 않습니다.

template을 특정 자료형으로 구체화해 놓는건
자료형에 따라서 자동(?)으로 그 구체화된 작업을 하게 만들기 위해서인데 (다형성)
위 방법으로 하면 그렇게 안되고 매번 자료형을 명시해 줘야 될꺼라 생각됩니다.

저렇게 구현할꺼면 차라리

verify_int()
verify_char()
verify_long()

하는게 더 나을거 같습니다.
쓸데없이 복잡하진 않으니까요. ^^
oosap의 이미지

순서가 뒤바뀌었지만 원래 문제는 아래와 같은 코드 입니다.
이 코드가 바로 VS 에서는 컴파일이 되지만 g++ 에서는 다음과같은 에러를 뱉어내고 있습니다.

'Explicit specialization in non-namespace scope'

아마도 C++03, §14.7.3/2: 를 위반하고 있는 모양입니다.

template<typename T>
class CConstraint
{
public:
    template <typename TL>
    void Verify(int position, int constraints[])
    {       
    }
 
    template <>
    void Verify<int>(int, int[])
    {   
    }
};

이 문제를 해결하는 코드를 스택오버플로에서 발견하고 KLDP 에서 그 의미를 확인한 것입니다.

다른 누군가가 'Explicit specialization in non-namespace scope' 를 만나서 KLDP 의 이 글을 발견하고 문제를 해결할 수 있기를 바랍니다. 또 저역시 나중에 이 쓰레드를 다시 찾으려 할 때 KLDP 가 그 자리에서 변함없이 이 글들을 보여주기를 바랍니다.

첨부파일은 좀 더 간단한 테스트 코드를 올려둡니다.

http://www.cantrip.org/traits.html

메타 함수와 Traits 는 같은 이야기를 하고 있는 것 같습니다.
우연히 발견하게 된 경위까지 이 글에서 읽을 수 있습니다.
내용 자체는 쉽게 이해가 되지는 않지만 일단 관련 내용이라서 여기에 링크를 올려둡니다.

http://www.boost.org/doc/libs/1_31_0/libs/type_traits/c++_type_traits.htm
http://accu.org/index.php/journals/442

이 두 쓰레드는 읽어보지도 못했지만 관련 내용이라 역시 올려둡니다.

http://stackoverflow.com/questions/7284956/what-is-the-template-trait-classes-in-c

스택오버플로가 항상 소스가 되는군요. 뭐든지 다 있습니다.

댓글 첨부 파일: 

Thanks for being one of those who care for people and mankind.
I'd like to be one of those as well.

댓글 달기

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
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.