在模板类中使用Lambda表达式

8

我正在尝试使用一个带有lambda函数参数的模板类,但我不知道如何传递这个参数。以下是我到目前为止尝试过的方法:

#include <iostream>
using namespace std;

template <class F>
class A {
public:

   int f(int i)
   {
       return F(i); //*
   }
};

int main(int argc, const char * argv[]) {
auto f = [](int i){return i+5;};
A<decltype(f)> a;
cout << a.f(5);
return 0;
}

我在标记的那行代码处遇到了一个错误。

有人能帮忙吗?


这个类中仅对于方法 f 是否需要类型 F - BiagioF
仅返回翻译后的文本:只有方法。 - Ofer Magen
F是一种类型(class F),那么F(i)的意思是什么? - Xiobiq
静态运算符(适用于C#) - Ofer Magen
2
Lambda表达式可以是有状态的(携带捕获)。在这种情况下,您的“静态方法”方法并不合理。 - Igor Tandetnik
3个回答

9

您的示例无法运行,因为F是一种类型,而不是可调用对象。下一步是通过创建成员变量来实例化它。

template <class F>
class A {
    F function;
public:
    int f(int i) {
         return function(i);
    }
};

然而,这仍然行不通,因为lambda默认构造函数被删除了。这意味着我们需要另一种方式来构造function。可以通过向A的构造函数传递参数来实现这一点。
template<typename F>
class A {
    F function;
public:
    A(const F& f) : function(f) {}
    int f(int i) {
        return function(i);
    }
};

// ...

auto f = [](int i) { return i+5; };
A<decltype(f)> a(f);

这里使用了lambda拷贝构造函数,该函数并未被删除。

实时示例

如果您希望它与任何lambda一起工作,可以添加更多的魔法。

template<typename F>
class A {
    F function;

public:
    A(const F& f) : function(f) {}

    template<typename ...Args>
    auto f(Args... args) -> std::result_of_t<F(Args...)> {
        return function(std::forward<Args>(args)...);
    }
};

Live example


4

如果您真的想使用模板来接受任何类型的函数签名,那么实现应该类似于这样:

class A {
 public:
  template<typename F, typename... Args>
  auto f(F&& funct, Args&&... args) {
    return funct(std::forward<Args...>(args)...);
  }
};

由于你在评论中提到:

问:类中是否只有方法f需要类型F
答:仅限于该方法。

因此,在拥有模板方法的情况下,拥有模板类应该是无用的。

这里是一个示例,说明如何调用仅调用带其参数“可调用对象”的方法,本例中为lambda函数:

int main(int argc, char* argv[]) {
  A a;
  a.f([](int i) -> int { return i + 5; }, 12);
  //  |------callable object-----------|   |argument of function|
  return 0;
}

实际上,方法f将一个“可调用对象”作为第一个参数,并将任何请求的参数作为进一步的参数以便调用第一个参数。


附加说明:

如果你想传递给方法f一个特定类型的函数签名,例如:int (*)(int),那么你可以避免使用模板并传递一个std::function类型的对象。

这只是一个例子:

#include <functional>
class A {
 public:
  // method g accept a function which get a integer and return an integer as well.
  int g(std::function<int(int)> funct, int arg) {
    return funct(arg);
  }
};

正因为如此,当你可以使用模板方法时,拥有一个模板类就变得无用了。每次调用模板方法都需要传入lambda表达式。而一个模板类,例如与类型擦除结合,可以将实际的lambda隐藏在operator()后面。 - skypjack
@skypjack 这就是我问他是否只需要方法模板还是类模板的原因。如果问题更清楚地说明了 通用A 的目的,那么就更容易用具体的解决方案回答了。 - BiagioF

2

仅将A定义为从lambda函数继承或某种方式包含它是不够的,当您创建A的实例时,仍然必须初始化子对象。
例如,您可以从lambda继承并使用A作为可调用对象来完成这个任务。
下面是一个最小化的工作示例:

#include <iostream>

using namespace std;

template <class F>
class A: public F {
public:
    A(F f): F(f) {}
};

int main() {
    auto f = [](int i){return i+5;};
    A<decltype(f)> a{f};
    cout << a(5);
    return 0;
}

您不必定义任何函数f执行lambda表达式。
但是,如果您想要一个函数fa.f(5)的形式被调用,您可以按照以下方式定义它:

int f(int i) {
    return F::operator()(i);
}

或者按照以下方式:
int f(int i) {
    return (*this)(i);
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接