传递 ref class 成员函数作为参数
Passing ref class member function as a parameter
我正在尝试创建一个包装器,允许 System::Task 在一个衬里中创建对象。到目前为止,我有以下工作 -
ref class TaskRunner abstract sealed
{
public:
generic<typename TArg0>
static Task^ Create(Action<TArg0>^ f, TArg0 arg0) {
return Task::Run((gcnew BindAction1<TArg0>(f, arg0))->binder);
}
private:
generic<typename TArg0>
ref class BindAction1
{
initonly TArg0 _arg0;
Action<TArg0>^ const f;
void _() { return f(_arg0); }
public:
initonly Action^ binder;
BindAction1(Action<TArg0>^ f, TArg0 arg0) : f(f), _arg0(arg0) {
binder = gcnew Action(this, &BindAction1::_);
}
};
}
可以通过-
调用
auto task = TaskRunner::Create(gcnew Action<TArg0>(this, &Class::Function), arg0);
但是我想消除手动创建操作的需要。 IE。修改 Create 使调用看起来像-
auto task = TaskRunner::Create(this, &Class::Function, arg0);
并在 Create 中调用 gcnew Action(obj, func)。我不知道这是否可能。如果是这样,我将如何声明创建的参数?
实际上它们需要与 Action 委托相同。查看系统库 Action 似乎需要 System::Object 和 System::IntPtr 但我无法使用它们作为参数来使其工作。
*更新 - 感谢 IllidanS4 提供完整的答案以及您帮助完成这项工作。对于任何试图在他的答案中使用代码的人来说,Visual Studio 2015 中似乎存在一个编译器错误,它需要为每个参数链长度覆盖 delegate_type。
来自 ECMA-372:
A program that attempts to take the address of a member function of a non-native class in any context other
than in the creation of a delegate, is ill-formed. There is no pointer-to-member representation for members of
non-native classes.
不幸的是,这意味着 &Class::Function
无效。在我看来,这个限制是没有用的,因为 CIL 中的 ldftn
指令正是在委托构造中编译成的指令。遗憾的是,C++/CLI 中缺少一个 "pointer to managed function" 类型,尽管它显然存在于 CIL 中。
所以不,方法必须包含在委托中传递。但是,如果你对宏开放,你可以使用这样的东西:
#define CreateTask(obj, func, arg) TaskRunner::Create(gcnew System::Action<decltype(arg)>(obj, func), arg)
编辑:使它也适用于 Func 情况有点棘手,但它也适用于某些模板:
template <class Ret, class... Args>
struct delegate_type
{
using type = System::Func<Args..., Ret>;
};
template <class... Args>
struct delegate_type<void, Args...>
{
using type = System::Action<Args...>;
};
#define CreateTask(obj, func, arg) TaskRunner::Create(gcnew delegate_type<decltype(obj->func(arg)), decltype(arg)>::type(obj, &func), arg)
只是不要将它与 &Class::Function
一起使用,而是传递 Class::Function
。
我正在尝试创建一个包装器,允许 System::Task 在一个衬里中创建对象。到目前为止,我有以下工作 -
ref class TaskRunner abstract sealed
{
public:
generic<typename TArg0>
static Task^ Create(Action<TArg0>^ f, TArg0 arg0) {
return Task::Run((gcnew BindAction1<TArg0>(f, arg0))->binder);
}
private:
generic<typename TArg0>
ref class BindAction1
{
initonly TArg0 _arg0;
Action<TArg0>^ const f;
void _() { return f(_arg0); }
public:
initonly Action^ binder;
BindAction1(Action<TArg0>^ f, TArg0 arg0) : f(f), _arg0(arg0) {
binder = gcnew Action(this, &BindAction1::_);
}
};
}
可以通过-
调用auto task = TaskRunner::Create(gcnew Action<TArg0>(this, &Class::Function), arg0);
但是我想消除手动创建操作的需要。 IE。修改 Create 使调用看起来像-
auto task = TaskRunner::Create(this, &Class::Function, arg0);
并在 Create 中调用 gcnew Action(obj, func)。我不知道这是否可能。如果是这样,我将如何声明创建的参数?
实际上它们需要与 Action 委托相同。查看系统库 Action 似乎需要 System::Object 和 System::IntPtr 但我无法使用它们作为参数来使其工作。
*更新 - 感谢 IllidanS4 提供完整的答案以及您帮助完成这项工作。对于任何试图在他的答案中使用代码的人来说,Visual Studio 2015 中似乎存在一个编译器错误,它需要为每个参数链长度覆盖 delegate_type。
来自 ECMA-372:
A program that attempts to take the address of a member function of a non-native class in any context other than in the creation of a delegate, is ill-formed. There is no pointer-to-member representation for members of non-native classes.
不幸的是,这意味着 &Class::Function
无效。在我看来,这个限制是没有用的,因为 CIL 中的 ldftn
指令正是在委托构造中编译成的指令。遗憾的是,C++/CLI 中缺少一个 "pointer to managed function" 类型,尽管它显然存在于 CIL 中。
所以不,方法必须包含在委托中传递。但是,如果你对宏开放,你可以使用这样的东西:
#define CreateTask(obj, func, arg) TaskRunner::Create(gcnew System::Action<decltype(arg)>(obj, func), arg)
编辑:使它也适用于 Func 情况有点棘手,但它也适用于某些模板:
template <class Ret, class... Args>
struct delegate_type
{
using type = System::Func<Args..., Ret>;
};
template <class... Args>
struct delegate_type<void, Args...>
{
using type = System::Action<Args...>;
};
#define CreateTask(obj, func, arg) TaskRunner::Create(gcnew delegate_type<decltype(obj->func(arg)), decltype(arg)>::type(obj, &func), arg)
只是不要将它与 &Class::Function
一起使用,而是传递 Class::Function
。