2015-01-27 5 views
6

는 현재 내가 템플릿과 같이 있습니다템플릿 포인터를 함수로 분해 할 수있는 방법이 있습니까?

template<typename func, typename ret, typename... args> class Entry{ 
public: 
    PVOID Address; 
    ret operator()(args...){ 
     return ((func) this->Address)(args...); 
    } 
}; 

그리고 나는 이런 식으로 사용하고 있습니다

Entry<int(*)(int), int, int> func; 
// ^func  ^ret ^args 
func.Address = (PVOID) 0xDEADC0DE; 
func(123); // calls 0xDEADC0DE with '123' as argument 

을 그러나, 나는 궁금해서 그것이 가능하다면 만이 가지고 :

Entry<int(*)(int)> func; 
// ^only specifying the function's prototype once instead of breaking it down 
func(123); 

만약 내가 그것을 좋아한다면, 나는 함수 포인터 타입을 인자와 리턴 타입으로 나눌 수 없으므로 operator()을 오버로드 할 수 없을 것이다. return_type operator()(args...) 작성).

이것을 달성 할 방법이 있습니까? 내가 VS2013 십일 사용하고

2013 CTP

당신은이 같은 전문화와 함께 할 수
+1

'void *'에 함수 포인터를 저장하는 데 기술적 인 문제가 있다고 생각했습니다. 확실히 어떤 플랫폼 VS2013 타겟이 아니더라도, 나는 인정할 것이다. – Yakk

+0

@ Yakk, 함수 포인터 (정상 포인터보다 훨씬 큽니다)의 크기 때문일 수 있습니다. 그러나 나는'& function'을하지 않습니다. 나는 수출 테이블에서 주소를 가져 와서 캐스팅합니다. 어떤 해를 끼치 지 않아야합니다. – rev

답변

5

: 내가 좋아하지만 (

// Entry has one template argument 
template<typename func> class Entry; 

// and if it's a function type, this specialization is used as best fit. 
template<typename ret, typename... args> class Entry<ret(args...)>{ 
public: 
    PVOID Address; 
    ret operator()(args... a){ 
    return ((ret(*)(args...)) this->Address)(a...); 
    } 
}; 

int main() { 
    Entry<int(int)> foo; 
    foo.Address = (PVOID) 0xdeadc0de; 
    func(123); 
} 

이 예에서와 같이 함수 포인터 유형을 사용하려면 기능 유형 구문 이상), 쓰기

//           here ------v 
template<typename ret, typename... args> class Entry<ret(*)(args...)>{ 

부록 다음 operator() 그쪽으로와 (약간의) 문제가 있습니다 : 나는 밖으로 저녁 식사를 얻고 때 한가지 더 내게 임하여 당신이 염려 할 수도 있고 그렇지 않을 수도 있습니다 : 전달 된대로 전달 되었기 때문에 값 또는 lvalue 참조로 전달 된 매개 변수에 전달 문제가 발생하지 않습니다 (인수 목록은 함수 포인터 및 operator())하지만 rvalue- 참조 매개 변수를 사용할 계획이라면 암시 적으로이를 수행 할 수 없습니다. 이러한 이유 때문에

Entry<int(int&&)> foo; 
foo(123); 

이 컴파일되지 않습니다. 당신이를 rvalue 참조를 가지고 기능이 사용하려는 경우, operator()은과 같이 해결할 수 있습니다 : @Wintermutes 포스트에 표시된

ret operator()(args... a){ 
    //     explicit forwarding ----v 
    return ((ret(*)(args...)) this->Address)(std::forward<args>(a)...); 
} 
+0

이것으로 전화 협약을 지정할 수 있습니까? 'Entry foo;'와 AND 형식 구문을 사용합니까? 아니면 함수 포인터를 사용해야합니까? – rev

+1

MSVC 2013에서'Entry foo;'를 사용할 수 있습니다.'__stdcall'은 표준의 일부가 아니므로 다른 컴파일러가 지원하지 않을 것입니다. – Wintermute

+0

놀라운. 이제는 클래스에 생성자를 추가하려고 시도했습니다 :'Entry foo (0xC0DE);','불완전한 타입이 허용되지 않습니다. ' 유형 구문을 사용하고 있습니다. 내가 뭘 놓치고 있니? – rev

1

부분 특수화로 가능하다.
그러나 그것없이 가능해야한다 하려는지 :

template <typename func> 
class Entry{ 
public: 
    PVOID Address; 

    template <typename... Args> 
    auto operator()(Args&&... args) 
    -> decltype(((func*) Address)(std::forward<Args>(args)...)) { 
     return ((func*) Address)(std::forward<Args>(args)...); 
    } 
}; 

템플릿 인수는 함수 유형이어야합니다. 즉

template <typename... Args> 
auto operator()(Args&&... args) 
-> decltype(((typename std::remove_pointer<func>::type*) Address)(std::forward<Args>(args)...)) { 
    return ((typename std::remove_pointer<func>::type*) Address)(std::forward<Args>(args)...); 
} 

Demo, typename std::remove_pointer<func>::type*를 사용하는 대신 캐스트의 목표 유형으로 func*을 사용하는 그러나, 당신은 반환 표현에 약간의 수정 가지는 형태를 작동하려면 두 기능과 포인터로 작업 할 수 있습니다.

0

메타 프로그래밍 방법. 첫째, 호출 규칙 정보를 유지하려고하는 포인터 특성입니다.

template<class...>types {using type=types;}; 
enum class calling_convention { 
    cdecl, 
    clrcall, 
    stdcall, 
    fastcall, 
    thiscall, 
    vectorcall, 
}; 
template<class Sig> 
struct signature_properties; 
template<class R, class...Args> 
struct signature_properties { 
    using return_type = R; 
    using argument_types = types<Args...>; 
};  
template<class FuncPtr> 
struct function_properties; 
#define CAT_(A,B) A##B 
#define CAT(A,B) CAT_(A,B) 

#define CALLING_CONVENTION_SUPPORT(CONVENTION) \ 
    template<class R, class... Args> \ 
    struct function_properties< R(CAT(__, CONVENTION) *)(Args...) >: \ 
    signature_properties<R(Args...)> \ 
    { \ 
    using type = R(CAT(__, CONVENTION) *)(Args...) \ 
    static const calling_convention convention = calling_convention::CONVENTION; \ 
    static type from_pvoid(void const* pvoid) { \ 
     return static_cast<type>(pvoid); \ 
    } \ 
    } 
CALLING_CONVENTION_SUPPORT(cdecl); 
CALLING_CONVENTION_SUPPORT(clrcall); 
CALLING_CONVENTION_SUPPORT(stdcall); 
CALLING_CONVENTION_SUPPORT(fastcall); 
CALLING_CONVENTION_SUPPORT(thiscall); 
CALLING_CONVENTION_SUPPORT(vectorcall); 
#undef CAT 
#undef CAT_ 
#undef CALLING_CONVENTION_SUPPORT 

Icky 매크로. 그리고 심각한 과잉. 그리고 안된다고. 그러나 당신은 아이디어를 얻습니다.

다음 작업을 할 수있는 도우미 : 도우미의

template<class FuncPtrType, class R, class Args> 
struct helper; 
template<class FuncPtrType, class R, class... Args> 
struct helper<FuncPtrType, R, types<Args...>> { 
    FuncPtrType ptr; 
    R operator()(Args...args)const { 
    return ptr(std::forward<Args>(args)...); 
    } 
    helper(FuncPtrType p):ptr(p) {}; 
    helper(helper const&)=default; 
    helper& operator=(helper const&)=default; 
}; 

완벽한 전달도 유혹 할 것이다.

마지막으로, 우리는 helperEntry에서 작업을 반송 위의 특성 클래스를 사용

template<class FuncPtrType> 
struct Entry:helper< 
    FuncPtrType, 
    typename signature_properties<FuncPtrType>::return_type, 
    typename signature_properties<FuncPtrTpye>::arguments 
> { 
    using parent = helper< 
    FuncPtrType, 
    typename signature_properties<FuncPtrType>::return_type, 
    typename signature_properties<FuncPtrTpye>::arguments 
    >; 
    Entry(void const* pvoid):parent(static_cast<FuncPtrType>(pvoid)) {} 
}; 

우리가 void const*을 가지고 helper에 입력 된 포인터를 전달하는 Entry의 생성자를 포함 제외.

한 가지 변경 사항은 에서 우리가 호출 한 시점이 아닌 함수 유형이라는 것을 알고있는 가장 빠른 시점에 함수 유형으로 변환한다는 것입니다.

관련 문제