在模板类中使用lambdas

时间:2016-09-03 16:20:57

标签: c++ templates c++11 lambda

我正在尝试使用带有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;
}

我在标记的行中收到错误。

有人可以帮忙吗?

3 个答案:

答案 0 :(得分:8)

您的示例不起作用,因为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拷贝构造函数,它没有被删除。

Live example

如果你想让它与任何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

答案 1 :(得分:3)

如果你真的想使用模板来接受任何类型的功能签名,那么实现应该类似于:

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

那是因为你在评论中说过:

  

问:仅在方法F的类中是否需要类型f
  答:只有方法

因此,当你可以使用模板方法时,拥有模板类应该没用。

这里是一个示例,如何调用只调用&#34;可调用对象及其参数&#34; 的方法,在本例中为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接受第一个参数a&#34; 可调用对象&#34;并且作为进一步的参数,为了调用第一个参数而请求任何参数。

附加说明:

如果要向方法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);
  }
};

答案 2 :(得分: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。
无论如何,如果你想让一个函数f被称为a.f(5),你可以按照以下方式定义它:

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

或者如下:

int f(int i) {
    return (*this)(i);
}