객체내의 멤버 변수를 사용하는 함수의 포인터를 어떻게 지칭할
글쓴이: neocoin / 작성시간: 월, 2003/04/28 - 1:59오전
부딪친 문제에 대한 간단한 예를 작성해 보았습니다.
다음과 같은 소스가 있습니다.
하고 싶은 의도는 comment 해놓은 것과 비슷합니다.
어떻게 해야 할까요?
// 실행 가능한 코드 #include <iostream> #include <algorithm> #include <vector> using namespace std; class Element{ public: int data; Element(int aData){ data = aData; } }; /// 이 코드(start~end)를 Logic class 내부에 넣고 싶습니다. // start int times = 0; void printE(Element elem){ times++; cout << times << "번째 실행 " << elem.data << endl; } // end class Logic{ public: vector<Element> datas; Logic(){ for ( int i= 0; i< 10; i++){ Element element(i); datas.push_back(element); } } void run(){ ::times = 0; for_each(datas.begin(), datas.end(), printE); } }; int main(){ Logic logic; logic.run(); }
즉, Logic class 가 이렇게 되기를 원하는 것이지요.
// 실행 불가능한 코드 class Logic{ public: vector<Element> datas; Logic(){ for ( int i= 0; i< 10; i++){ Element element(i); datas.push_back(element); } } int times; void printE(Element elem){ times++; cout << times << "번째 실행 " << elem.data << endl; } void run(){ times = 0; // this->printE 이것이 불가능합니다. for_each(datas.begin(), datas.end(), this->printE); } };
보시는 바와 같이, 상태 유지를 위한 class 내의 변수 times가 필요한 상황
입니다. 그래서, 멤버 함수의 포인터를 넘기고 싶은데, 이것이 힘듭니다.
물론, functor 를 쓰면 어느정도 가능합니다. 다음과 같이 말이지요.
// 제일 첫번째 예제의 Element class 와 main 코드가 있으면 돌아갑니다. class Logic{ public: vector<Element> datas; Logic(){ for ( int i= 0; i< 10; i++){ Element element(i); datas.push_back(element); } } class PrintE{ public: int times; PrintE() : times(0){} void operator() (Element elem) { this->times++; cout << times << "번째 실행" << elem.data << endl; } }; void run(){ for_each(datas.begin(), datas.end(), PrintE()); } };
하지만 배보다 배꼽이 더 큰 형상이 되어 버리는것 같습니다.
어떻게 하면 짧고, 명쾌하게 넘길수 있을까요?
Forums:
굳이, 아래와 같이 하면 printE를 Logic class안으로 넣고,
굳이, 아래와 같이 하면 printE를 Logic class안으로 넣고, for_each2로 한방에 해결할 수 있기는 합니다.
아시다시피, c++에서는 instance의 method를 호출할 때, instance객체인 this가 implicit하게 첫 parameter로 넘어갑니다.
따라서, template 함수인 for_each 에 함수 pointer만 알려줘서는 제대로 instance의 method를 호출할 수가 없고, instance 자체를 알려줘야 합니다.
하지만 standard template library에는 vector내에 들어있는 instance들에게 적용하는 것만 있으므로, 이 경우 당연히 template를 따로 만들어 줘야 합니다. 그래서 새로 만든 template 함수가 for_each2입니다.
하지만 저같으면 저렇게 하지 않고, 그냥
처럼 하겠습니다.[/code]
답변 감사드립니다.
'c++에서는 instance의 method를 호출할 때, instance객체인 this가 implicit하게 첫 parameter로 넘어갑니다. '
을 몰랐습니다. 왜? 라는 것에는 답변이 되었습니다.
그리고 뒷부분의
을 지양하려는 이유는 이것이 의미 전달에 실패하고 있다고 생각해서 입니다.
for_each(datas.begin(), datas.end(), this->printE)
를 사용이 가능하고, 더 나아가
for_each(datas, this->printE)
로 사용한다면, 더 명시적이고(for-each) 짧은 코드(1/3)로 판단되어 가능성을 알아보고 싶었습니다. (물론, 두번째 코드는 STL 알고리즘이 container뿐만 아니라 배열을 수용한다는 면에서 구현이 안되었다는 점이 아깝습니다. 다른 알고리즘들도 때문에 코드가 늘어나지요.)몇 가지 아이디어에 대한 개인적인 욕심도 있었는데, 다른 가능성을 생각해 봐야 겠습니다. 그리고 왜 CppUnit(http://cppunit.souceforge.net) 가 그런
형태인지 이해가는 계기가 되었습니다. 감사합니다.
binder
이럴 때마다 functor를 만드는게 번거롭기 때문에 c++ standard library에서는 binder, adapter, negator 라는 놈들을 제공합니다. (더 자세한 것은 stroustrup의 책을 참고하세요)
boost에는 이걸 좀 더 편하게 할 수 있게 해주는 bind라는 놈을 제공하고요
lambda라는 놈도 있지만 vc6에서는 컴파일이 안되기 때문에 저는 주로 boost::bind를 사용합니다.
안타깝게도 vc6에서 run()은 컴파일이 안되는 군요;;
(mem_fun가 zero parameter인 method에만 적용되고 bind1st는 return type이 void인 function에는 적용되지 않는 것 같습니다. 혹시 피해갈 수 있는 방법 아는 분은 알려주세요)
댓글 달기