주의 : 공부하면서 정리한 것이기 때문에 오류가 있을 수 있습니다.
실습 과제 4-4 :
정수 연산자들과 형식 특질 라이브러리의 수단을 이용해서 다음의 합성 특질들을 구현하라.
is_data_member_pointer
is_pointer_to_function
is_reference_to_function_pointer
is_reference_to_non_const
풀이 :
이 문제는 논리 연산자들을 적절하게 사용해 메타 함수를 합성하는 방법을 알고 있는지 확인하는 문제이다.
일단 함수를 합성하기 위해서는 문제에 나온 함수를 각각의 ( 함수 ) 요소로 분해할 수 있어야 한다.
1. is_data_member_pointer
이 메타 함수는 다음과 같이 분해된다.
is_data_member_pointer = is_member_pointer && !( is_member_function_pointer )
그리고 나서 이 함수를 테스트하는데 사용할 class 를 정의해 보자.
그런데 여기에서 문제가 발생한다. 우리가 만든 메타 함수는 매개변수로 type 을 받아 들이므로 우리가 테스트하고 싶어하는 field 의 형식에 어떻게 접근해야 할지 알 수 없다는 것이다. 예를 들어 다음과 같이 테스트하는 것은 오류이다.
그래서 C++ 0x 부터 추가된 decltype 을 사용해 봤다. 그런데 다음과 같은 결과가 나온다.
결국 어떻게 테스트해야 하는지 알수 없어서 CPPTM Answers - Exercise 4-4 를 참조했다. 여기에서는 빈 클래스인 foo 를 선언하고, typedef 를 통해서 새로운 type 을 선언했다. 일단은 그렇게 테스트를 해 봤다.
나중에 member variable 에서 class 까지 포함하는 type 을 획득할 수 있는 방법에 대해서 알아 봐야 겠다.
2. is_pointer_to_function
이 문제는 함수 포인터의 본질에 대해서 얼마나 이해하고 있느냐를 확인하고 있다. 처음에는 다음과 같이 생각했다.
is_pointer_to_function = is_function || is_member_function_pointer
그런데 "왜 is_function 은 is_function_pointer 가 아닌 것일까?" 라는 의문이 들기 시작했고, 다른 사람의 구현을 살펴 보았다.
http://www.crystalclearsoftware.com/cgi-bin/boost_wiki/wiki.pl?CPPTM_Answers_-_Exercise_4-4
사실 함수포인터는 그냥 함수라고 생각했었는데, 지금까지 아주 잘못된 생각을 하고 있다는 것을 알았다. 일반적인 변수와 유사하게 함수 자체도 변수처럼 동작하는 것이었다. 그래서 여기에서 함수 포인터에 대해 다시 짚어 볼 필요가 있었다. 다음은 함수 포인터의 예이다. 다음 링크에서 가지고 온 예이다 : Program as Data: Function Pointers
위의 예에서 마치 변수의 주소를 구하듯이 함수의 주소를 구하는 것을 볼 수 있다. 변수는 어떤 메모리 공간에 대한 이름이다. 그리고 그 이름은 어떠한 주소로 매핑된다. 위에서도 언급했듯이 변수와 마찬가지로 함수는 어떤 로직을 담고 있는 메모리 공간에 대한 이름이 되겠다. 그러므로 이것도 참조하거나 포인팅하는 것이 가능한 것이다. 특이한 점은 그 포인터 자체에 () 연산자를 걸어서 호출이 가능하다는 것이다. () 연산자에 대해서는 다음 글을 참조하기 바란다 : [ 번역 ] Function Call Operator ().
그런데 위의 구현은 한 가지 문제가 있다. mpl::and_ 의 두 번째 매개 변수에서 ::type 을 지정함으로써 지연 평가가 이루어지지 않는다는 것이다. 이를 지연 평가가 가능하게 고쳐 보려고 했는데 잘 되지 않았다. 이 부분도 연구해 볼 필요가 있다.
어쨌든 is_pointer_to_function 은 다음과 같은 표현이라고 할 수 있다.
is_pointer_to_function = is_pointer && ( is_function( remove_pointer ) )
그리고 위의 구현은 불필요하게 and_ 를 호출하고 있기 때문에 최종적으로는 다음과 같이 구현할 수 있다.
3. is_reference_to_function_pointer
점점 복잡해 지고 있다. 하지만 function 에 대해서 이해한 상황이기 때문에 그리 어려울 것은 없다. 앞에서 만들었던 is_pointer_to_function 을 재사용하고, boost::remove_reference 로 reference 를 제거해 주기만 하면 된다.
is_reference_to_function_pointer = is_reference && ( is_pointer_to_function( remove_reference ) )
코드는 다음과 같다.
4. is_reference_to_non_const
이 문제는 비교적 쉬운데 다음과 같이 표현할 수 있다.
is_reference_to_non_const = is_reference && !( is_const( remove_reference ) )
코드는 다음과 같다.
여기에서 의문을 가지는 사람이 있을 것이다. 왜 is_const 에서 remove_reference 를 해야 하는 것일까? 필자가 다음과 같이 test 했을 때 error 를 냈다.
아직까지 그 이유는 정확하게 모르겠지만 추측해 보면, boost 의 type traits 는 특정 순서대로 한정자를 제거해 가면서 type check 를 하도록 만들어져 있는 것 같다.
'Programming > CPPTM' 카테고리의 다른 글
[ 번역 ] How Do Those Funky Placeholders Work? (0) | 2013.01.03 |
---|---|
C++ Template Metaprogramming 실습 과제 2-6 풀이 (0) | 2012.12.31 |
C++ Template Metaprogramming 실습 과제 4-5 풀이 (0) | 2012.12.28 |
C++ Template Metaprogramming 실습 과제 4-3 풀이 (0) | 2012.12.13 |
C++ Template Metaprogramming 실습 과제 4-2 풀이 (0) | 2012.12.13 |
C++ Template Metaprogramming 실습 과제 4-1 풀이 (0) | 2012.12.12 |
C++ Template MetaProgramming 실습 과제 4-0 풀이 (0) | 2012.12.10 |
C++ Template MetaProgramming 실습 과제 3-7 풀이 (0) | 2012.12.01 |
C++ Template MetaProgramming 실습 과제 3-6 풀이 (0) | 2012.12.01 |
C++ Template MetaProgramming 실습 과제 3-5 풀이 (0) | 2012.11.29 |