0

내 앱에서 레거시 함수 시그너처를 통해 매개 변수 팩을 전달하고 값을 변경하고자합니다. 내 시도를 코멘트로 묘사 한 코드는 다음과 같습니다.forward_as_tuple을 사용하여 레거시 함수 시그너처에 매개 변수 팩 전달

#include <tuple> 
#include <cassert> 

void LegacySignature(void* param); 

template< typename... ArgsT > 
// using ???; // attempt: can 'template alias' or 'using declaration' make the pack's type visible so I can use it inside the LegacyFunction? 
void MyFunc(ArgsT&... args) 
{ 
    auto userArgsTuple = std::forward_as_tuple< ArgsT&... >(args...); 

    LegacySignature(&userArgsTuple); 
} 

void LegacySignature(void* param) 
{ 
// auto userArgsTuple = reinterpret_cast<???>(param); // attempt: how can I get the parameter pack's type declared so I can use it here? 

    // do something with the params like change num to 44 and tf to true; 
    //userArgsTuple->num = 44; // desired functionality 
    //userArgsTuple->tf = true; // desired functionality 
} 

int main() 
{ 
    int num { 33 }; 
    bool tf { false }; 
    MyFunc(num, tf); 
    assert(num == 44 && tf == true); 

    return 0; 
} 

매개 변수 팩을 선언 가능한 왼쪽 값으로 만드는 방법이 있습니까?

+0

그들은 콜백을 전달하기를 원합니다. 콜백은'void *'와 그것들이 제공하는 다른 arg를 취한다. 당신은'void * '를 통해 어떤 데이터를 전달하기를 원합니다. 그래서 그것은 다른 끝에서 다시 당신에게 전달됩니다. 그들은 당신이 통제 할 수있는 고정 범위보다 콜백이나'void * '를 저장하지 않을 것입니다. 이 올바른지? 질문 :'void *'가 콜백 함수의 첫 번째 매개 변수 또는 마지막 매개 변수로 전달 되었습니까? – Yakk

+0

'void *'를 사용하는 것은 실제 서명을 토론을위한 중립적 인 형식으로 표현하려는 나의 시도 일뿐입니다. 실제로 실제 서명 매개 변수는 오래된 'LPARAM'입니다. MS의 상태에 따라 WPARAM과 LPARAM은 모두 "다형성 값을 전달하고 반환하는 데 사용되는 유형"입니다. 따라서 콜백이 전달되거나 내 질문에 호출됩니다. 필자의 관심은 스마트 포인터에서 값을 변경할 수있는 레퍼런스 인 임의의 수의 인수를 전달하는 방법을보다 잘 이해하는 데있다. – rtischer8277

+0

참고로, 'future'를 사용하여 레거시 서명에 대한 콜백 문제를 해결했습니다. StackOverflow 문제 [PostThreadMessage를 사용하여 shared_ptr을 어떻게 사용할 수 있습니까?] (http://stackoverflow.com/questions/25667226)에서 시작하는 답변을 찾아보십시오. * @ Remy Lebeau와 @ rtischer8277은 지금까지 내 원래 게시물에 두 개의 답변을 제출했습니다 ... *. – rtischer8277

답변

0

아래 코드는 샘플 코드를 수정하여 forward_as_tuple을 사용하여 레거시 함수 서명에 매개 변수 팩을 전달하는 방법에 대한 질문에 대답합니다.

#include <tuple> 
#include <cassert> 
#include <memory> 
#include <functional> 

#define ARGSET int, bool 

void LegacySignature(long* param); // ie, LPARAM 

template< typename... ArgsT > 
struct MyParams 
{ 
    MyParams(ArgsT... args) : rvalRefs { std::forward_as_tuple(args...) } {} // The resulting forward_as_tuple tuple has rvalue reference data members 
    std::tuple<ArgsT...> rvalRefs; 
}; 


void LegacySignature(long* legSigParam) 
{ 
    auto userArgsTuple(reinterpret_cast< MyParams<ARGSET>* >(legSigParam)); 

    // do something with the params like change num to 44 and tf to true; 
    std::get<0>(userArgsTuple->rvalRefs) = 44; // index types can probably be worked out using enums 
    std::get<1>(userArgsTuple->rvalRefs) = true; 
} 

int main() 
{ 
    int num { 33 }; 
    bool tf { false }; 
    MyParams<ARGSET> myParams(num, tf); 

    std::unique_ptr< MyParams<ARGSET> > legSigParamPtr = std::make_unique< MyParams<ARGSET> >(myParams); 
    LegacySignature((long*)legSigParamPtr.get()); 
    assert(std::get<0>(legSigParamPtr->rvalRefs) == 44 && std::get<1>(legSigParamPtr->rvalRefs) == true); 

    return 0; 
} 
0

내가 원하는 것은 기존 서명에 대한 함수 포인터입니다.

다음은 C++ 11 접근 방식입니다.

template<class Sig, class F> 
struct magic_callback_t; 

template<class R, class...Args, class F> 
struct magic_callback_t<R(Args...), F> { 
    F f; 
    void* pvoid() const { return this; } 
    using result_sig = R(*)(void*, Args...); 
    result_sig pfunc() const { 
    return [](void* pvoid, Args...args)->R{ 
     auto* self = static_cast<magic_callback_t*>(pvoid); 
     return (self->f)(std::forward<Args>(args)...); 
    }; 
    } 
}; 
template<class Sig, class F> 
magic_callback_t<Sig, F> magic_callback(F&& f) { 
    return {std::forward<F>(f)}; 
} 

이제 우리는이 작업을 수행 :

auto callback = magic_callback([&](){ 
    // use whatever as if we where in the enclosing scope 
}); 

void(*)(void*) legacy_ptr = callback.pfunc(); 
legacy_ptr(callback.pvoid()); 

magic_callback에 전달 된 람다를 호출합니다.

튜플로 물건을 저장하려는 경우 할 수 있습니다. 람다에서 튜플을 캡처 한 다음 std::get을 사용하여 람다 본문에 액세스하십시오. 변경할 수 있으려면 mutable을 사용하십시오.

+0

우수한 콜백 솔루션. 그러나 기본적으로 스레드를 전환하고 매개 변수로 전달 된 대상 스레드에서 기존 함수를 동기식으로 실행하고 값을 동 기적으로 반환해야합니다. My * SendThreadMessage * 솔루션에서는 여러 매개 변수 전달을 제외하고이 작업을 수행하도록 지시했습니다. 샘플 코드에 설명 된 임의 매개 변수 전달 방식은보다 나은 디자인입니다. 콜백 솔루션은 불행하게도 비동기식입니다. 나는 항상 원시 ptr을 고유하거나 공유 된 obj로 전달할 수 있지만 호출자의 개발 작업을 더 어렵게 만듭니다. – rtischer8277