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 *'和一些其他的參數。你想通過'void *'傳遞一些數據,所以它會在另一端傳回給你。他們不會存儲您的回調或您的'void *'超過您控制的固定範圍。它是否正確?問題:是否將'void *'作爲回調函數的第一個或最後一個參數傳遞? – Yakk

+0

使用'void *'僅僅是爲了討論,我試圖將實際簽名表示爲中性類型。事實上,實際的簽名參數是'long'這個古老的'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拉姆達。

如果你想存儲東西作爲一個元組,你可以。只需在lambda中捕獲元組,然後使用std::get在lambda的主體中訪問它。如果您希望它是可變的,請使用mutable

+0

優秀的回撥解決方案。然而,我的基本需求是切換線程,在目標線程中同步執行一個現有函數,可能會傳入參數,並同步返回值。我指出,我* SendThreadMessage *解決方案是這樣做的,除了傳遞多個參數。示例代碼中概述的任意參數傳遞引用方法是更好的設計。回調解決方案不幸是異步的。我總是可以將一個原始ptr傳遞給一個獨特的或共享的obj,但這會使得調用者的開發工作變得更加困難。 – rtischer8277