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

本文关键字:语法 以及 用法 lambdas 泛型 C++ | 更新日期: 2024-10-20 20:25:12

在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
});

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

您所拥有的几乎可以在语法上工作;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),但就你而言,这可能是正确的

std::function<void(T)> myFunctionDelegatedelegate void myFunctionDelegate<T>(T arg) 的(非常)粗略等价物

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

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

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