调用存储在映射中的模板化std::函数
Calling a templatized std::function stored in a map
我正试图创建一个基类,该基类将存储信号(以int
的形式),并允许我稍后使用它们来调用派生类指定的函数。它们存储在unordered_map
中,因为这正是我所需要的——1个信号=1个函数(加上它很快)。
不过,我在给他们打电话时遇到了一些麻烦,收到了一个巨大的错误,形式是:
调用"(
std::unordered_map<int, std::function<void()>, std::hash<int>, std::equal_to<int>, std::allocator<std::pair<const int, std::function<void()> > > >::mapped_type
{又名std::function<void()>
})(int&, int&)
"不匹配
编译错误来自signals_[_sig](args...);
const int SIGCHANGE = 1;
template<typename... Args>
class Signal {
private:
std::unordered_map< int, std::function<void(Args...)> > signals_;
inline void SetSignal(const int& _sig, std::function<void(Args...)> _func) {
signals_[_sig] = _func;
}
public:
Signal() {}
~Signal() {}
template<typename... Ts>
void Sig(const int& _sig, Ts... args) {
if (signals_.find(_sig) != signals_.end()) {
signals_[_sig](args...);
}
}
};
class Obj : public Signal<> {
private:
int num_;
public:
Obj* child;
void Change(int _num) {
num_ = _num;
child->Sig(SIGCHANGE, _num);
}
void HandleChanged(int _num) {
num_ = _num;
}
};
int main() {
Obj* obj1 = new Obj();
Obj* obj2 = new Obj();
obj1->child = obj2;
obj1->Change(10);
}
此外,我不知道我是否正确使用了模板——我上次使用这些模板已经很久了。每个函数都应该有自己的模板吗?如果我想将模板用于成员变量,为什么必须在类之前指定模板?
由于函数只有一个int
参数,因此需要有
class Obj : public Signal<int>
而不是
class Obj : public Signal<>
后者创建了一个具有原型void()
函数的映射,而您需要一个原型void(int)
函数。
此外,模板化Sig
函数是无用的,因为无论如何都不能用除Args
之外的任何其他参数集来调用它。所以它可以只是
void Sig(const int& _sig, Args... args) {
if (signals_.find(_sig) != signals_.end()) {
signals_[_sig](args...);
}
}
如果您的目标是支持使用任意原型存储函数,那么需要以不同的方式来实现,基本上是通过运行时多态性(映射中的所有项都需要是相同的类型,因此类型本身需要在后台进行调用多态性)。
编辑
根据信号类型定义功能原型的一种可能性。要求信号int始终作为编译时间常数传递-特定信号类型的不同函子存储在std::tuple
:中
const int SIGZERO = 0;
const int SIGCHANGE = 1;
const int SIGOTHER = 2;
// non-specialized template intentionally left empty
// (or can provide default prototype)
template<int SIG>
struct SignalPrototype;
template<>
struct SignalPrototype<SIGZERO>
{
typedef std::function< void() > type;
};
template<>
struct SignalPrototype<SIGCHANGE>
{
typedef std::function< void(int) > type;
};
template<>
struct SignalPrototype<SIGOTHER>
{
typedef std::function< void(int, int) > type;
};
class Signal {
private:
std::tuple<
SignalPrototype<SIGZERO>::type,
SignalPrototype<SIGCHANGE>::type,
SignalPrototype<SIGOTHER>::type
> signals_;
protected:
template<int SIG>
inline void SetSignal(typename SignalPrototype<SIG>::type _func) {
std::get<SIG>(signals_) = _func;
}
public:
template<int SIG, typename... Ts>
void Sig(Ts... args) {
SignalPrototype<SIG>::type func = std::get<SIG>(signals_);
if (func)
func(args...);
}
};
struct MyHandler : SignalPrototype<SIGCHANGE>::type
{
void operator()(int x)
{
std::cout << "Called MyHandler with x = " << x << std::endl;
}
};
class Obj : public Signal {
private:
int num_;
public:
Obj* child;
Obj()
{
SetSignal<SIGCHANGE>(MyHandler());
}
void Change(int _num) {
num_ = _num;
child->Sig<SIGZERO>();
child->Sig<SIGCHANGE>(_num);
child->Sig<SIGOTHER>(1, 2);
}
void HandleChanged(int _num) {
num_ = _num;
}
};
(一般来说,Signal作为Obj的成员而不是继承可能会更好)
- 使用std::函数映射对象方法
- 可组合的lambda/std::函数与std::可选
- 当使用透明的std函数对象时,我们还需要写空的尖括号吗
- std::函数常量正确性未遵循
- 具有变量Number of Arguments的std::函数的矢量
- 从类型std::函数传递变量失败,尽管调用方期望的类型完全相同
- 如何调用存储在指向"std::函数"的指针中的 lambda?
- C++ STD 函数运算符:有没有一种方法可以通过函数将一个向量映射到另一个向量上?
- 从具有按值捕获的 lambda 移动构造 std::函数时,移动构造函数调用两次
- 如何将类 1 的 std::函数绑定到类 2 的函数?
- 如何制作可以接受任何类型的参数的 std::函数和 lambda
- 如何将 STL 队列推送函数绑定到 std::函数?
- std::函数不起作用,但普通的旧函数指针可以 - 为什么?
- 获取 std::函数以推断按引用传递/按值传递
- std::bind 和 std::函数术语不值为接受 0 个参数?
- 从其存储的回调中删除 std::函数是否安全
- 创建 std::函数,它返回具有函数成员值的变量.分段错误
- 创建一个带有 lambda 的 std::函数,而不知道函数的参数
- std::函数的解释
- 在调用过程中删除 std::函数