[英]C++ Variadic function with inherited objects references and base class
我正在編寫一個類來實現和信號槽機制。 該信號可以發出一系列事件,這些事件都源自一個名為“base_event”的基本結構。 下面是我如何定義 base_event 和派生結構的示例:
struct base_event
{
std::string _id = "base_event";
};
struct select_next_event : public base_event
{
select_next_event(uint32_t tr_num) : base_event(), _tr_num(tr_num)
{
base_event::_id = "select_next_event";
};
uint32_t _tr_num;
};
然后我的發射函數簽名是:
template<typename... Args>
void emit(Args... args)
{
..... All the logic .....
}
然后,當我想發出一個事件時,我會寫如下內容:
slot.emit(select_next_event{3});
到那里為止,一切正常。
我的問題是我想在我的庫中添加一個異步(非阻塞)發射函數。 為了實現這個目標,我編寫了第二個函數(我使用的是 c++20,所以我可以進行完美的轉發):
void emit_async(Args... args)
{
auto send_async = std::async(std::launch::async,
[this, ... args = std::forward<Args>(args)](){ emit(std::forward<Args>(args)...); });
}
如果我這樣寫,就會出現問題:
slot.emit_async(select_next_event{3});
然后當我在我的槽函數中讀取事件時, _tr_num的值不會被轉發(總是等於 0)
但是,如果我寫:
auto send_async = std::async(std::launch::async,
[this](){slot.emit(select_next_event{3});});
然后_tr_num的值被正確地轉發給 slot 函數。
我看不到我的錯誤在哪里?
皮爾
[編輯]
根據要求,很抱歉我不夠清楚,請在下面找到一個演示我的問題的最小示例:
#include <iostream>
#include <utility>
#include <future>
#include <vector>
struct base_event
{
std::string _id = "base_event";
};
struct select_next_event : public base_event
{
select_next_event(uint32_t tr_num) : base_event(), _tr_num(tr_num)
{
base_event::_id = "select_next_event";
};
uint32_t _tr_num;
};
template<typename... Args>
void emit(Args... args)
{
int i = 0;
([&] (auto & arg)
{
++i;
std::cout << "input " << i << " = " << arg._id.c_str() << " " << arg._tr_num << std::endl;
} (args), ...);
}
template<typename... Args>
void emit_async(Args... args)
{
auto send_async = std::async(std::launch::async,
[... args = std::forward<Args>(args)](){ emit(std::forward<Args>(args)...); });
}
int main()
{
emit(select_next_event{3});
//emit_async(select_next_event{3}); // if added, it produces a compilation eror
}
我使用以下代碼編譯代碼:
g++ -std=c++20 -O2 -Wall -pedantic -pthread main.cpp && ./a.out
我認為這個例子提出了我遇到的問題,就好像我刪除了異步的注釋一樣,我確實有一個編譯錯誤:
main.cpp:38:82: error: binding reference of type ‘std::remove_reference<select_next_event>::type&’ {aka ‘select_next_event&’} to ‘const select_next_event’ discards qualifiers
我確實希望現在我已經對我的問題做出了更清晰的解釋! 如果有任何遺漏/誤導,請告訴我!
這里有兩個問題。
首先, emit_async(Args... args)
是按值傳遞的,所以Args...
始終是值類型,您需要為其添加轉發引用。
其次,更重要的是,您使用init-capture [... args = std::forward<Args>(args)]
構造args
,但由於 lambda 的operator()
是隱式const
,因此您不能在函數體中轉發args
,因為args
也是const
限定的,而不是您需要為 lambda 添加mutable
關鍵字
template<typename... Args>
void emit_async(Args&&... args) {
auto send_async = std::async(
std::launch::async,
[...args = std::forward<Args>(args)] mutable
{ emit(std::forward<Args>(args)...); });
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.