C#通用委托的C ++等效语法,以及lambdas的用法

时间:2015-03-06 01:25:38

标签: c# c++ templates generics

在C#中,我可以这样做:

delegate void myFunctionDelegate<T>(T arg);

在C ++中,我理解我需要为函数指针的模板使用别名,但语法是如此奇怪,以至于我发现的所有示例都让我更加困惑。

以下是错误的;我怎么能纠正它?

template<typename T>
using myFunctionDelegate = void (*)(T arg);

我想这样使用它:

template<class T> class Foo
{
    ...
    void someOtherFunction(myFunctionDelegate callback)
    {
        ...
        callback(someValue);
    }
}

然后:

myClassInstance.someOtherFunction([&](T arg) {
    // do something with the callback argument
});

2 个答案:

答案 0 :(得分:3)

你几乎在语法上有所作为;使用myFunctionDelegate只需要一个类型参数:

void someOtherFunction(myFunctionDelegate<T> callback)
                                         ^^^

如果您没有从中获得任何特别的好处,别名参数名称是可选的:

template<typename T>
using myFunctionDelegate = void(*)(T);

然而,存在一个更大的问题:函数指针不处理状态。示例调用中使用的lambda通过捕获它来使用state。因此,捕获lambda不能转换为函数指针。如果传递这样的lambda非常方便,函数参数应该支持。

这有两种常见的方式。第一种是忘记强制特定的返回和参数类型。相反,让调用者传递任何可以按函数调用它的方式调用的对象(lambda,函数指针,仿函数,std::bind的结果):

template<typename Callable>
void someOtherFunction(Callable callback) {
    ...
    callback(someValue);
}

如果调用不起作用,代码将无法编译 1 (但遗憾的是,这个错误并不太有用,但未来Concepts会增加可以轻松帮助那里。)

另一方面,您可能希望显式指定函数类型。 C ++有一个通用类型来存储任何可调用对象(参见上面的列表)。该类型为std::function。它比一个简单的模板参数更重要,但在你需要它时很有用。

template<typename T>
using myFunctionDelegate = std::function<void(T)>;

void someOtherFunction(const myFunctionDelegate<T> &callback) {...}

[1]:这并不总是正确的(参见SFINAE),但它可能就你所关注的那样。

答案 1 :(得分:2)

std::function<void(T)> myFunctionDelegatedelegate void myFunctionDelegate<T>(T arg)

的(非常)粗略等价物

std::function<void(T)>遵循值语义(它的行为更像是int而不是C#对象引用),这会使事情变得不同。

lambda闭包([](T t){/*code*/})的生命周期(或其副本)超出本地范围不应使用基于&的捕获。而是使用基于=的捕获(可能需要额外的工作)。如果您调用的代码在调用的生命周期之外没有存储代理的副本,则[&]是最佳的。在C ++中,数据的生命周期是您需要关注的事情。

这不是关于lambdas和std::function如何工作的完整教程,而只是为了指出正确的方向。