具有继承对象引用和基数 class 的 C++ 可变参数函数
C++ Variadic function with inherited objects references and base class
我正在编写 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;
};
那么我的 emit 函数签名是:
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的值就正确的转发给槽函数了
我没看到我的错误在哪里?
Pi-r
[编辑]
根据要求,很抱歉我不够清晰,请在下面找到一个证明我的问题的最小示例:
#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
我希望现在我已经对我的问题做出了更清晰的解释!如果有什么 missing/misleading,请告诉我!
这里有两个问题。
首先,emit_async(Args... args)
是传值,所以Args...
始终是值类型,需要加上转发引用
其次,也是更重要的一点,您使用 init-capture [... args = std::forward<Args>(args)]
构造了 args
,但是由于 lambda 的 operator()
隐式 const
,你不能在函数体中转发 args
因为 args
也是 const
限定的,相反你需要为 lambda[=22= 添加 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)...); });
}
我正在编写 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;
};
那么我的 emit 函数签名是:
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的值就正确的转发给槽函数了
我没看到我的错误在哪里?
Pi-r
[编辑]
根据要求,很抱歉我不够清晰,请在下面找到一个证明我的问题的最小示例:
#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
我希望现在我已经对我的问题做出了更清晰的解释!如果有什么 missing/misleading,请告诉我!
这里有两个问题。
首先,emit_async(Args... args)
是传值,所以Args...
始终是值类型,需要加上转发引用
其次,也是更重要的一点,您使用 init-capture [... args = std::forward<Args>(args)]
构造了 args
,但是由于 lambda 的 operator()
隐式 const
,你不能在函数体中转发 args
因为 args
也是 const
限定的,相反你需要为 lambda[=22= 添加 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)...); });
}