簡體   English   中英

具有繼承對象引用和基類的 C++ 可變參數函數

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM