C++로 지연된 함수콜 구현하기

지난 2일 간

관해서 포스팅했다. 오늘 이걸 실제로 광범위하게 적용시켜봤는데, 그러다 보니 문제점들이 확실히 보였다.

테스트 하는 동안 가장 문제가 되었던 것은 참조형으로 넘겨준 변수 문제였다. (포인터로 넘겨주는 일은 “없다고 가정하는 상황"이라서 일단 그 문제는 넘어가자)

class A : private boost::noncopyable {
public:
  A() {}
  virtual ~A() {}
  void Do3(int a, int b, int& c) {
    cout << "A::Do3(" << a << ", " << b << ", " << c << ")" << endl;
  }
};

void foo() {
  A a;
  int tmp_val = 3;
  shared_ptr<Closure> c = MakeClosure<A, void, int, int, int&>(a, &A::Do3, 1, 2, tmp_val);
  c->Execute();
  tmp_val = 0;
  c->Execute();
}

foo 의 실행결과는 다음과 같다. (foo에서 Closure를 만드는 부분의 타입 추론 문제 때문에 템플릿 인자를 명시적으로 썼다)

A::Do3(1, 2, 3)

A::Do3(1, 2, 0)

_지금 구현한 것을 사용하는 곳에서 원하는 동작_은 두 번의 실행 모두 (1, 2, 3) 이라고 찍히는 것이다. 템플릿 클래스 멤버 변수들의 타입을 실행될 함수의 인자타입과 동일하게 했었는데, 이를 참조자 형태인 경우에만 원래의 타입이 되게 수정하는 코드를 넣었다. 즉, 원래

A0 m_A0;

A1 m_A1;

처럼 선언되던 것을, boost::remove_reference<T> 를 사용해서1

typename boost::remove_reference<A0>::type m_A0;

typename boost::remove_reference<A1>::type m_A1;

로 선언되게 수정했다. 그러고 나니 원하는 대로의 출력이 나오게 되었다.

이제 남은 문제: MakeClosure 라는 보조 함수를 통해서 템플릿 인자 타입을 자동 연역하게 했었는데, 참조형인 경우에는 이게 제대로 되지 않는다. 뭘 해주면 이걸 자동으로 찾을까? 즉, 위에 사용한 코드의 MakeClosure 부분의 템플릿 인자 목록을 지우면, “int인지 int&인지 모호하다.” 라는 에러가 나오게 되는데(VC++ 2005기준) 이를 피할 방법은 없을까? 라는 것.


  1. boost::remove_reference<T><boost/type_traits/remove_reference.hpp> 에 정의되어 있다. T가 어떤 타입 U의 참조형(U&)일 때만 U로 바꿔준다. T가 그렇지 않은 타입인 경우 그대로 T를 돌려주게 된다. ↩︎