2009-07-15 4 views
6

기본적으로 형식을 수동으로 지정하지 않고도 제네릭 C 함수에 대한 래퍼를 생성하려고합니다. 그래서 고정 된 프로토 타입으로 콜백을 가지고 있지만 래퍼 함수의 유형에 따라 래퍼에서 특별한 코드를 수행해야 할 것입니다. 그래서 기본적으로 클래스 템플릿에서 정적 메서드를 사용하려고합니다.유형이 아닌 템플릿 매개 변수 ... 템플릿입니다. (C++)

// this is what we want the wrapped function to look like 
typedef void (*callback)(int); 
void foobar(float x); // wrappee 

// doesn't compile 
template< T (*f)(S) > // non-type template param, it's a function ptr 
struct Wrapper 
{ 
    static void wrapped(int x) 
    { 
    // do a bunch of other stuff here 
    f(static_cast<S>(x)); // call wrapped function, ignore result 

    } 
} 

를 그리고 내가 좋아하는 일을하고 싶습니다 : 규격에 부합하는 인터페이스 예를 들어 내 기능을 포장하는

AddCallback(Wrapper<foobar>::wrapped); 

그러나, 문제는 내가 그냥 앞서 및 사용에 갈 수 있다는 것입니다 래퍼 템플릿의 함수 매개 변수에 "S"가 있으면 먼저 매개 변수로 나열해야합니다.

template< class T, class S, T (*f)(S) > 
struct Wrapper 
// ... 

그러나이 말은()을 사용하는 것이 훨씬 더 고통 스럽다는 것을 의미합니다. 이상적으로는 함수 포인터를 전달하고 매개 변수의 유형 (및 반환 유형)을 자동으로 처리하고 싶습니다. 명확하게 말하면, 래핑 된 함수 내에서 함수 포인터의 유형을 참조해야 할 것입니다 (그래서 나는 S 또는 T와 동등한 것이 필요합니다).

이 방법이 있습니까?

+0

@damndirtyape : 귀하의 질문에 대해 생각해 보았습니다. 비슷한 것을 시도한 것 같습니다. 불행히도 많은 코드가 필요했습니다. 기본적으로, 내 솔루션은 operator()를 오버로드 한 기본 클래스를 갖고 있으며 함수 유형을 기반으로 기본 클래스를 생성 한 팩토리 함수를 가졌습니다. 당신이 좋아한다면 나는 어딘가에 pastebin에 코드를 게시 할 수 있습니다. –

답변

0

"wrapped"를 직접 참조하지 않고 반환하는 함수를 사용하는 경우 컴파일러는 함수 호출에 대한 템플릿 매개 변수를 자동으로 일치 시키려고 시도합니다.

편집 : 이것에 대해.

int foobar(float x); // wrappee 

template <typename T, typename S> 
struct Wrapper { 
    typedef T (*F)(S); 
    F f; 

    Wrapper(F f) : f(f) { } 

    void wrapped(S x) { 
     // do a bunch of other stuff here 
     f(x); // call wrapped function, ignore result 
    } 
}; 

template <typename T, typename S> 
Wrapper<T,S> getWrapper(T (*f)(S)) { 
    return Wrapper<T,S>(f); 
} 

... 
getWrapper(foobar).wrapped(7); 
+0

그 문제에 대한 템플릿 매개 변수가 같은 문제를 가지고 있기 때문에 문제가 해결되지 않습니다. – damndirtyape

+0

정말입니까? 어쩌면 나는 단지 당신이 무엇을하려고하는지 이해하지 못한다. ... –

+0

함수를 정적 메서드에서 인스턴스 메서드로 변경했기 때문에 작동하지 않지만 전체적인 점은 래핑 된 함수가 기존 콜백 서명 (이는 정적이어야 함을 의미). – damndirtyape

0

편집 : 완전히 새로운 대답

OK, 나는 완전히 질문을 다시 생각 난 당신이 원하는 것을 얻을 수 있다고 생각했습니다. 나는 전에 이것을 실제로했다 :-P.

다음은 개념입니다. operator()를 오버로드하는 Base 클래스가 있고 함수의 각 "arity"에 대한 하위 클래스가 있습니다. 마지막으로 나는이 중 하나를 리턴 할 팩토리 함수를 가지고있다. 코드는 크고 (아마도 약간의 잔인 함이 있지만) 멋지게 작동합니다. 대부분의 library_function 오버로드는 다른 구문을 지원하며 대개 불필요합니다. 또한 boost::bind 함수, 멤버 함수 등을 지원합니다.

http://pastebin.com/m35af190

예, 사용은 :

// map of library functions which will return an int. 
std::map<std::string, LibraryFunction<int> > functions; 

// function to register stuff in the map 
void registerFunction(const std::string &name, LibraryFunction<int> func) { 
    functions.insert(std::make_pair(name, func)); 
} 

나중에는이 작업을 수행 할 수 있습니다

// the this param is so the function has access to the scripting engine and can pop off the parameters, you can easily chop it out 

// register 2 functions, one with no params, one with 1 param 
registerFunction("my_function", library_function1(*this, call_my_function)); 
registerFunction("my_function2", library_function0(*this, call_my_function2)); 

functions["my_function"](); 
functions["my_function2"](); 
+0

이것은 기존 함수를 래핑 할 수 없기 때문에 새로운 객체를 작성해야합니다. 즉, 추측하는 대신 앞에 형식을 지정해야한다는 의미입니다. – damndirtyape

+0

그게 어떻게 도움이되는지 모르겠습니다. 기본적으로 나는 특정 콜백 서명을 가지고있다.이 콜백 서명을 준수하기 위해 다수의 기존 C 함수를 감쌀 필요가있다. (스크립트 바인딩 일이기 때문에 3 개의 매개 변수 함수에 대해 팝업해야한다. 3 값을 스택에서 빼고 래퍼로 전달한 다음 스택에 결과를 푸시합니다. 그러나 외부 적으로 모든 단일 함수는 동일한 서명을가집니다. – damndirtyape

+0

또, 그건 내가 도움이되지 않습니다. 고정 콜백 서명과 호환되는 함수 포인터로 변환해야합니다. 이것은 그렇게하지 않습니다. 함수 내에서 문자열 (스택에 문자열을 밀어 넣는 등)을 수행하여 콜백에 해당하는 함수로 문자열을 전달하는 함수를 돌릴 필요가 있지만이 래핑 된 함수의 서명은 반드시 *해야합니다. 콜백에 해당합니다. – damndirtyape

0

나는 부스트보고 싶은데. 귀하의 질문에 대한 첫 번째 읽기에서 그것은 내게 보이는 것보다 <boost/function_types/parameter_types.hpp> 귀하의 필요를 제공합니다.

+0

정말 좋은 대답은 아닙니다. 적어도 관심있는 부스트 라이브러리를 지적하지 않고서는 "Google에서 검색, 대답은 거기에 있다고 생각합니다"라고 말하는 것과 같습니다. 게다가 OP 요구 사항을 충족시킬 수있는 Boost에는 아무것도 표시되지 않습니다. 당신의 대답에 좀 더 구체적으로 대답 해 주시겠습니까? –

+0

나는 가지고 있었다. 직접 HTML 엔터티 대신 < 외 >을 사용했으며 헤더 이름이 숨겨졌습니다. 나는 그것을 해결하기 위해 내 대답을 편집했습니다. – AProgrammer

+0

의견에서 엔티티가 필요 없으며 < and >이 작동합니다 ... 음, 아직 인터페이스를 배우고 있습니다. – AProgrammer

5

당신이 고려하고 싶은 한 가지 점은 런타임시 적절한 트램펄린 기능을 생성하기 위해 LLVM 또는 유사한 것을 사용하는 것입니다.또는 정적 솔루션은 다음과 같습니다.

#include <iostream> 

void f(float f) { std::cout << f << std::endl; } 

template<typename T, typename S> struct static_function_adapter { 
     template<T(*f)(S)> struct adapt_container { 
       static void callback(int v) { 
         f(static_cast<S>(v)); 
       } 
     }; 

     template<T(*f)(S)> adapt_container<f> adapt() const { 
       return adapt_container<f>(); 
     } 
}; 

template<typename T, typename S> struct static_function_adapter<T, S> get_adapter(T (*)(S)) { 
     return static_function_adapter<T, S>(); 
} 

#define ADAPTED_FUNCTION(f) (&get_adapter(f).adapt<f>().callback) 

int main() { 
     void (*adapted)(int) = ADAPTED_FUNCTION(f); 
     adapted(42); 
     return 0; 
} 

get_adapter 함수를 사용하면 인수와 반환 유형을 추론 할 수 있습니다. 그런 다음 adapt()를 실제 함수에서 매개 변수화 된 유형으로 변환하고 마지막으로 콜백에서 정적 함수를 얻습니다.

+0

나는이 코드가 무엇을해야하고 어떤 문제를 해결해야하는지 전혀 모른다. O – Virus721

관련 문제