함수객체에 대해서... 도움을 부탁드립니다

doogie의 이미지

여러 class의 동일한 이름, 인자의 함수를 미리
stl::map에 등록해놓고 필요할때마다 key를 검색해서
함수를 호출하는 로직을 짜고 있습니다.

테스트 코드를 짜는 중에 어떻게 할지 몰라 이렇게 글을
올립니다.
클래스의 멤버 함수를 호출하고 또 여러 클래스의 멤버함수를
호출하는 거라 함수 포인터 대신에 함수 객체를 이용하고
있습니다.

테스트 환경은 vc++.net입니다.

에러가 나는 소스입니다.

#include "stdafx.h"
#include <functional>
#include <map>

using namespace std;

class C1
{
public:
	bool call (int c, string s)
	{
		printf ("int : %d, string : %s\n", c, s.c_str ());
		printf ("press enter: "); getchar ();
		return true;
	}
};

class C2
{
public:
	bool call (int c, string s)
	{
		printf ("int : %d, string : %s\n", c, s.c_str ());
		printf ("press enter: "); getchar ();
		return true;
	}
};

template <class T>
struct functor
{
public:
	functor (T t) : X (t)
	{
	}

	bool operator () (int c, string s) const
	{
		return X.call (c, s);
	}
private:
	T & X;
};

typedef map <int, functor <class T> > FMap;

int _tmain(int argc, _TCHAR* argv[])
{
	FMap fMap;

	int c = 1;
	string s = "this is test";

	C1 t1;
	functor <C1> f1 (t1);
	fMap.insert (make_pair (1, f1));

	//C2 t2;
	//functor <C2> f2 (t2);
	//fMap.insert (make_pair (2, f2));

	//FMap::const_iterator iter = fMap.find (1);
	//if (iter != fMap.end ())
	//	(iter->second) (c, s);

	return 0;
}

VC++의 에러메시지는 다음과 같습니다.

Quote:
error C2664: 'functor<T>::functor(T)' : 매개 변수 1을(를) 'const functor<T>'에서 'T'(으)로 변환할 수 없습니다.
컴파일 중인 함수 템플릿 인스턴스화 'std::pair<_Ty1,_Ty2>::pair<int,functor<T>>(const std::pair<int,functor<T>> &)'에 대한 참조를 확인하십시오.

어떤 부분에서의 잘못으로 에러 메시지가 나오는지 잘 모르겠습니다.
그리고 위의 struct funtor 대신에 boost::function을 사용해도 될듯 한데 어찌 해야 할지도 잘 모르겠습니다.

소스의 잘못된 부분이나 해결책을 가르쳐주시면 감사하겠습니다 ^^

happyjun의 이미지

typedef map <int, functor <class T> > FMap; 
FMap fMap;

functor<class T> 의 T는 실제 타입 이어야 합니다. functor<C1> 이나 functor<C2> 와 같이 되어야 합니다.

functor<>는 정적 다형성 static polymorphism을 구현하고 있기 때문에 동적 다형성 dynamic polymorphism과 같이 컨테이너에 넣을 수 없습니다.

이런 경우의 일반적인 패턴은 그냥 동적 다형성을 이용하는 것입니다.

C1, C2의 부모 클래스를 만들어서 사용하는 것입니다.

class FunctionInterface
{
public:
    virtual ~FunctionInterface() {}
    virtual bool call (int c, string s);
};

class C1 : public FunctionInterface;
class C2 : public FunctionInterface;

typedef map <int,  shared_ptr<FunctionInterface> > FMap;

int main()
{
    FMap fMap;
    fMap.insert( make_pair(1, shared_ptr<FunctionInterface>( new C1() ) ) );
    fMap.insert( make_pair(2, shared_ptr<FunctionInterface>( new C2() ) ) );
 
    //
    int c = 1;
    string s = "this is test"; 

    fMap[1]->call( c, s );
}

boost::function을 사용하시려면 순수한 functor를 입력값으로 주시던가 boost::bind 등을 사용하셔야 합니다.

typedef boost::function<bool (int c, string s)> functionType;
typedef map< int, functionType > FMap;

FMap fMap;
fMap.insert( make_pair(1, bind( &C1::call, shared_ptr<C1>( new C1() ) ) ) );

fMap[1] ( c, s );

제 생각에는 boost::function, boost::bind 를 이용해서 std::map 에 function dispatch 기능을 넣은 것은 부자연스럽게 보이고 복잡합니다.

부족한 제 소견으로 전체 디자인 자체를 바꿔 보시는 것이 좋을 듯 합니다.

간단한 문제이면 문제를 올리시는 것이 더 재미있을 것 같습니다.

ps. 컴파일 시간에 fMap[n] 중 n 이 결정되는 경우는 template Metaprogramming 을 이용할 수도 있습니다.

----------------------------------------
http://moim.at
http://mkhq.co.kr

doogie의 이미지

친절한 답변 감사합니다... :D

이걸 하려는 목적은 네트웍 소켓에서 데이터를 받아서 처리할 클래스의 함수를 미리 map에 집어넣고 그때 그때 호출해서 처리하려고 한겁니다.

비동기 소켓이고 Window Programming이다 보니 간단하게
함수포인터 또는 함수객체로 처리하면 쉽겠다 싶어서 코딩하는 중인데 이것도 만만한게 아니군요 :shock:

static 한 class를 map에 넣기 때문에 역시나 안될듯 한 느낌이 오긴 했는데 happyjun 님의 답변을 보니 명확해졌습니다. ^^*
그리고 interface를 만들기는 힘들 듯 하니 boost::function을 사용하는 것도 역시 안될듯 합니다.

이 글을 올리기 전에 boost의 metafunction쪽을 대략 읽어보긴했는데 무슨 말인지 골치아프더군요 ^^*
다시 한번 boost::mpl을 보고 골치를 좀 앓아야 할 듯 합니다. ^^

언제나 처음처럼 ~~

gimmesilver의 이미지

각각의 소켓에서 받은 데이터를 처리한다면 굳이 템플릿을 이용할 필요없이 동적 다형성을 이용하더라도 문제가 없을 듯 싶군요...
위에 happyjun님이 말씀하신 것처럼 각각의 클래스들을 베이스 클래스로 묶고 함수 객체가 받는 클래스 타입을 베이스 클래스 타입으로 하시는 것이 가장 무난한 선택이 아닌가 생각합니다.

------------------------
http://agbird.egloos.com

댓글 달기

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