C++ 模板化委托,如 Unity
C++ Templated Delegates like Unity
看到 Unity 的委托和事件后,我正在尝试编写自己的代码:
我想创建一个带有可变参数模板的 class,以指定函数的 return 类型和可选参数。
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...);
}
};
如您所见,我希望 class 以这种方式使用:
MyDelegate<void> voidDelegate;
MyDelegate<void, int> intDelegate;
MyDelegate<int, char, boolt> miscDelegate;
和 "adding" 函数分别使用 += 运算符,例如:
voidDelegate += voidFunc;
//etc...
我现在遇到了 += 操作符的问题,因为 VS 不接受这个:
MyDelegate<void, int> delegate1;
delegate1 += [](const int a)->void{std::cout << a << std::endl; };
lambda 函数是正确的:它接受一个 int 和 return void,所以我不明白哪里错了。
问题是您的 std::vector
存储了函数指针。它不存储 std::bind
对象,不存储成员函数,不存储仿函数,也不存储 lambda。您正在尝试向其中添加一个 lambda,因此失败了。
如果你想存储任何类型的支持调用正确参数和 return 类型的对象,你需要 std::function
:
using FunType = std::function<Ret(Args...)>;
std::vector<FunType> vec;
顺便说一句,您可以通过完美转发您的 operator()
参数并在界面中复制您的 newElement
参数并将其移动到 std::vector
.
您的委托只接受函数指针。 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+
到那个时候你一定要使用 对 std::function
的建议。
@TartanLlama 说的对,std::function就是你需要的
并且调用循环可以折叠到for (auto handler : vec) handler(args...);
看到 Unity 的委托和事件后,我正在尝试编写自己的代码: 我想创建一个带有可变参数模板的 class,以指定函数的 return 类型和可选参数。
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...);
}
};
如您所见,我希望 class 以这种方式使用:
MyDelegate<void> voidDelegate;
MyDelegate<void, int> intDelegate;
MyDelegate<int, char, boolt> miscDelegate;
和 "adding" 函数分别使用 += 运算符,例如:
voidDelegate += voidFunc;
//etc...
我现在遇到了 += 操作符的问题,因为 VS 不接受这个:
MyDelegate<void, int> delegate1;
delegate1 += [](const int a)->void{std::cout << a << std::endl; };
lambda 函数是正确的:它接受一个 int 和 return void,所以我不明白哪里错了。
问题是您的 std::vector
存储了函数指针。它不存储 std::bind
对象,不存储成员函数,不存储仿函数,也不存储 lambda。您正在尝试向其中添加一个 lambda,因此失败了。
如果你想存储任何类型的支持调用正确参数和 return 类型的对象,你需要 std::function
:
using FunType = std::function<Ret(Args...)>;
std::vector<FunType> vec;
顺便说一句,您可以通过完美转发您的 operator()
参数并在界面中复制您的 newElement
参数并将其移动到 std::vector
.
您的委托只接受函数指针。 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+
到那个时候你一定要使用 std::function
的建议。
@TartanLlama 说的对,std::function就是你需要的
并且调用循环可以折叠到for (auto handler : vec) handler(args...);