2015-07-10 67 views
1

看到Unity的代表和事件,我试图编写我自己的代码: 我想用variadic模板创建一个类,指定函数的返回类型和optionals参数。C++模板化代表像Unity一样

template <typename Ret, typename... Args> 
class MyDelegate{ 
    std::vector<Ret(*)(Args...)> vec; 

    public: 
    void operator+=(const Ret(*)(Args...)& newElement) 
    { 
     vec.push_back(newElement); 
    } 


    Ret operator()(const Args&... args) 
    { 
     for (auto i = vec.begin(); i != vec.end(); ++i) 
      (*i)(args...); 
    } 
}; 

正如你可以看到,我想这个类这样使用:

MyDelegate<void> voidDelegate; 
MyDelegate<void, int> intDelegate; 
MyDelegate<int, char, boolt> miscDelegate; 

并使用+ =运营商,如 “加入” 功能分配到每个之一:

voidDelegate += voidFunc; 
//etc... 

我现在遇到+ =运算符的问题,因为VS不接受这个:

MyDelegate<void, int> delegate1; 
delegate1 += [](const int a)->void{std::cout << a << std::endl; }; 

lambda函数是正确的:它需要一个int并返回void,所以我不明白最新的错误。

+0

紧密相关的话题(延迟调度),你会发现[**这个问题,和顶级的答案**](http://stackoverflow.com/ a/7858971/1322972)特别有趣。它无时无刻地为我派上用场。 – WhozCraig

回答

3

问题是你的std::vector存储函数指针。它不存储std::bind对象,它不存储成员函数,它不存储函子,也不存储lambdas。你正试图给它添加一个lambda,因此失败。

如果你想存储任何类型的对象,它支持用正确的参数调用和返回类型,你想std::function

using FunType = std::function<Ret(Args...)>; 
std::vector<FunType> vec; 

Demo

顺便说一句,你可以通过perfect-提高您的解决方案转发您的operator()参数并将您的newElement参数复制到界面中并将其移动到std::vector中。

+0

如果你有std :: function的std :: vector,以后可能很难删除一个std :: function。通常情况下,如果你想从矢量中移除某些东西,你首先会得到一个迭代器,然后将迭代器传递给vector :: erase。在std :: function的情况下,查找将不起作用,因为std :: function的operator ==是...奇怪的(我不记得细节)。 相反,您可能想要使用类似的向量,其中unsigned是某种序列号。然后你可以在稍后使用该序列号。 – peterpi

+0

...我对这个问题非常熟悉的唯一原因是,我已经花了几天的时间在我的日常工作中做到这一点:) – peterpi

1

您的委托只接受函数指针。 lambda不是函数指针。然而,你正在尝试的lambda没有捕获任何东西。这意味着它可以被转换成一个函数指针感谢some sorcery

MyDelegate<void, int> delegate1; 
delegate1 += +[](const int a)->void{std::cout << a << std::endl; }; 
      ↑↑↑ 

然而,一旦你要允许有成员变量函数子,额外+将无法​​正常工作:

delegate1 += +[x](const int a) { ... }; // error: no match for operator+ 

在这一点上,你一定要使用TartanLlama的建议std::function

+0

嗯,这是一个很酷的把戏。你学到了一些新东西...... – TartanLlama

+1

@TartanLlama对于需要函数指针或Boost.Python的C库非常有用,你会认为它会允许函数,但是不会。 – Barry

0

@TartanLlama的权利,std :: function是你所需要的。

和主叫回路可以折叠for (auto handler : vec) handler(args...);