주의 : 공부하면서 정리한 것이기 때문에 오류가 있을 수 있습니다.


실습 과제 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 를 하도록 만들어져 있는 것 같다.


+ Recent posts