gpt4 book ai didi

c++ - 调用存储在映射中的模板化 std::function

转载 作者:太空狗 更新时间:2023-10-29 11:50:07 25 4
gpt4 key购买 nike

我正在尝试创建一个基类来存储信号(以 int 的形式)并允许我稍后使用它们来调用派生类指定的函数。它们存储在 unordered_map 中因为这正是我所需要的——1 个信号 = 1 个函数(而且速度很快)。

不过,我在调用它们时遇到了一些问题,出现了以下形式的巨大错误:

no match for call to ‘(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 {aka 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<>

后者创建一个带有函数原型(prototype) void() 的映射,而您需要一个函数原型(prototype) void(int)

此外,模板化 Sig 函数是无用的,因为无论如何您都无法使用 Args 以外的任何其他参数集来调用它。所以它可以简单地是

  void Sig(const int& _sig, Args... args) {
if (signals_.find(_sig) != signals_.end()) {
signals_[_sig](args...);
}
}

如果您的目标是支持存储具有任意原型(prototype)的函数,那确实需要以不同的方式完成,基本上是通过运行时多态性(映射中的所有项目都需要属于同一类型,因此类型本身需要在幕后进行调用多态性)。


编辑

根据信号类型定义函数原型(prototype)的一种可能性。要求信号整数将始终作为编译时常量传递 - 特定信号类型的不同仿函数存储在 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 的成员而不是继承实际上可能更好)

关于c++ - 调用存储在映射中的模板化 std::function,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41506712/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com