2009-09-04 4 views
1

this answer을 읽은 후 해결책이 있다고 생각했습니다. 적어도 거기에 대한 대답은 내가하고 싶은 것이지만 구현에 문제가 있습니다. 여기 boost :: function :: target을 사용하여 함수 포인터를 가져올 때 null 포인터

내가

typedef map<string, double*> myMap; 
typedef int (*ftwpt)(const char*, const struct stat*, int); 
typedef boost::function<int(const char*, const struct stat*, int)> MyFTWFunction; 

int myFunction(const char*, const struct stat*, int, myMap*); 

int main() 
{ 
myMap m_map; 
char tmpdir[] = "/tmp/mytmp"; 

MyFTWFunction f = boost::bind(myFunction,_1,_2,_3, &m_map); 

ftwpt* fpt = f.target<ftwpt>(); 
if (fpt) 
    status = ftw(tmpdir, *fpt, 50); 
else 
{ 
    cout << "Boost could not perform runtime conversion on function pointer" << endl; 
    return (EXIT_FAILURE); 
} 
} 

프로그램이 오류 또는 경고와 함께 컴파일을하려고하고있는 무슨의 개요입니다하지만 난 (FPT) 널 포인터를 얻고 것은) (f.target에서 반환; 런타임에. 부스트가 런타임 변환을 수행 할 수없는 경우 위의 stackoverflow 질문에 링크 된 참조에서 null 포인터가 반환되는 것 같습니다. Boost가 런타임 변환을 수행하지 못할 수도 있습니다. 어떤 아이디어?

+0

@Konrad 코드가 실패하는 이유도 설명 : http://stackoverflow.com/questions/282372/demote-boostfunction-to-a-plain-function-pointer/512233 # 512233 –

+0

@HazyBlueDot -이 질문은 C가 아니라 C가 아니라 C입니다. 올바르게 태그를 지정하십시오. –

답변

2

제대로 작동하려면 boost::function 개체에 저장하는 바인드 식의 정확한 형식을 알아야합니다. 객체 boost::bind(....)은 함수 포인터가 아닌 이상한 표현 템플릿입니다. 많은 boost::any처럼 -

이 필요한 이유, 기능이 operator() 팽창하지 않고, 원칙 가장 기본적인 구조이다

struct base { virtual ~base() { } }; 

template<typename T> 
struct derived : base { 
    derived(T t):t(t) { } 
    T t; 
}; 

struct function { 
    template<typename T> 
    function(T t) { 
    base *b = new derived<T>(t); 
    } 

    template<typename T> 
    T *target() { 
    if(typeid(*b) == typeid(derived<T>)) 
     return &static_cast< derived<T>* >(b)->t; 
    return 0; 
    } 

    base *b; 
}; 

에서 구현되는 방법 부스트 : 고려 이해합니다. 이 메커니즘은 타입 지우기 (type-erasure)라고 불립니다. 생성자는 임의의 타입의 객체를 받아 들인 다음 가상 함수 호출을 통해 접근 할 수있는 객체에 캡슐화 된 객체를 저장합니다 (boost::function은 자체 vtable 및 스택 할당을 사용하여 지옥처럼 최적화되었습니다. 작은 유형의 경우 new 등).

boost::function 개체에 할당 한 함수의 형식을 알고 있기 때문에 함수 포인터의 경우이 값이 효과적입니다. 복잡한 호출 가능 객체의 경우 더 이상 작동하지 않습니다.

하는 것이 아니라 바인딩식이, 노력하고 그냥 함수 포인터와 함께 작동하지 않습니다 있는지 볼 수, 당신은 무엇을 boost::bind 수익률의 유형을 알고 get_target 내에서 다음 코드

template<typename T> 
struct id { typedef T type; }; 

template<typename T> 
id<T> make_id(T) { return id<T>(); } 

struct any_type { 
    template<typename T> 
    operator id<T>() const { return id<T>(); } 
}; 

template<typename T, typename Fn> 
T *get_target(boost::function<Fn> &f, id<T>) 
{ return f.template target<T>(); } 

void f(int a, int b) { std::cout << a << " " << b << std::endl; } 

int main() { 
    boost::function<void(int)> g = boost::bind(&f, _1, 10); 
    (*get_target(g, true ? any_type() : make_id(boost::bind(&f, _1, 10))))(2); 
} 

을 고려 . 이를 사용하여 target 호출을 호출하고 boost::function 안에 감싸 인 객체를 반환 할 수 있습니다. main 내에 bind 식을 호출합니다. 이 코드 스 니펫이 어떻게 작동하는지 보려면 Eric Niebler의 기사 Conditional Love을 읽어보십시오.

+0

그럼 어떻게해야할까요? ftw에 대한 콜백 함수로 함수를 사용하고 싶지만 또한 콜백 및 결과를 넣는 데이터 구조에 대한 포인터를 전달하려고합니다. Boost.Bind가 이런 종류의 문제를 해결할 수 있어야합니다. 어떻게해야합니까? – HazyBlueDot

+0

왜'ftw'를 템플릿으로 만들지 않겠습니까? 그렇다면'boost :: bind'를 통해 함수 포인터에서'boost :: function'에 이르는 것을 받아 들일 수 있습니다. 템플릿으로 만들고 싶지 않다면 매개 변수 타입으로'boos :: function'을 사용하지 않을까요? 그것이 무엇을위한거야 : –

+0

나는 더 많은 세부 사항을 제공 했어야했다. ftw는 공유 라이브러리의 함수입니다 (linux.die.net/man/3/ftw의 man ftw를보십시오). 나는 매개 변수리스트를 제어하지 못합니다. – HazyBlueDot

1

다른 답변은 코드가 작동하지 않는 이유를 지적합니다. 어떤 제한된 상황에서 일종의 일종의 정말 못생긴 해결책이 있습니다.

typedef int (*ftwpt)(const char*, const struct stat*, int); 
typedef boost::function<int(const char*, const struct stat*, int)> MyFTWFunction; 

template <MyFTWFunction *callback> 
class callback_binder { 
public: 
    static int callbackThunk(const char *s, const struct stat *st, int i) { 
     return (*callback)(s, i); 
    } 
}; 

extern void register_callback(callback_t f); 

int random_func(const char *s, const struct stat *st, int i) 
{ 
    if (s && *s) { 
     return i; 
    } else { 
     return -1; 
    } 
} 

MyFTWFunction myfunc; 

int main(int argc, const char *argv[]) 
{ 
    myfunc = random_func; 
    register_callback(&callback_binder<&myfunc>::callbackThunk); 
    return 0; 
} 

포인터를 템플릿 인수로 사용하려면 포인터가 전역 변수에 대한 포인터가되어야합니다. 물론 전역 변수는 익명의 네임 스페이스에서 선언 될 수 있습니다.

추악한데, 동시에 호출 할 수있는 여러 개의 가능한 myMap 인스턴스를 가질 수있게하려면 가능한 한 많은 전역 MyFTWFunction 변수가 myMap의 가능한 동시 인스턴스가되어야합니다. 대부분이 전역 변수의 내용을 사용하여 누락 된 매개 변수를 채우는 썽크 함수 작성을 자동화합니다.여기

여기에 무슨 일이 일어나고 있는지 더 분명하게 할 수있다이 좁은 경우에 거의 같은 일을 훨씬 덜 유연 버전입니다 : 당신이 myMap_binder 볼 수 있듯이

#include <map> 
#include <string> 

using ::std::map; 
using ::std::string; 
typedef map<string, double*> myMap; 
typedef int (*callback_t)(const char *, struct stat *st, int); 

int myFunction(const char*, struct stat *st, int, myMap*); 

template <myMap **map_ptr> 
class myMap_binder { 
public: 
    static int call_my_function(const char *s, struct stat *st, int i) { 
     return myFunction(s, st, i, *map_ptr); 
    } 
}; 

extern void register_callback(callback_t f); 

myMap *mainmap; 
myMap *othermap; 

int main(int argc, const char *argv[]) 
{ 
    myMap m_map; 
    myMap m_map2; 
    mainmap = &m_map; 
    othermap = &m_map2; 
    register_callback(&myMap_binder<&mainmap>::call_my_function); 
    register_callback(&myMap_binder<&othermap>::call_my_function); 
    return 0; 
} 

템플릿입니다 전역 변수의 내용을 채우는 썽크 함수를 콜백 함수에 대한 호출로 자동 생성합니다.

0

이것은 몇 년 늦었지 만 나중에 도움이 될 것입니다. 내 문제는 약간 다르지만 솔루션에서 원하는 대답을 얻을 수 있습니다. 여기에 읽기 :
>Messaging system: Callbacks can be anything

다른 문제에