用状态创建C ++ 11 std::function<>
的最佳方法是什么?
在普通的C ++ 98中,我将创建一个继承自std::unary_function<>
或std::binary_function<>
的仿函数结构。因此,给定以下仿函数,如何从以下仿函数创建std::function<int(int)>
?
struct Functor
{
int x;
Functor(int val) : x(val) {}
int operator()(int val) { return val + x; }
};
int main()
{
Functor f(10);
int x = f(30);
}
请注意,上面的代码非常简化了我的需求。实际上,仿函数配置了多个参数并从文件中读取数据(其中每个记录比int更复杂)。有没有比使用lambdas更接近使用仿函数的解决方案?
修改:澄清
答案 0 :(得分:5)
最容易使用lambda表达式:
std::function<int(int)> f = [](int n) { return n + 30; }
您还可以使用std::bind
:
std::function<int(int)> f = std::bind(std::plus<int>, std::placeholders::_1, 30);
在这两种情况下,30
只是一个可以被捕获的变量替换的示例(确保将lambda中的捕获规范更改为[=]
,但是)最好使用类型auto
,以避免在只需要某些可调用类型时创建function
对象的潜在代价。
答案 1 :(得分:2)
使用Lambdas:
int x = 0;
std::function<int (int)> add = [x](int val) { return x + val; }
auto add2 = [x](int val) { return x + val; }
这里,lambda可以访问的变量在方括号中。 x作为副本传递。您还可以通过在“&amp;”前面添加一个状态作为参考。并捕获'this'
答案 2 :(得分:1)
你可以继续在C ++ 11中使用仿函数和类,事实上std::bind
和std::function
现在是C ++ 11标准的一部分,而之前它们是升级的一部分库,并在tr1中支持或作为各种标准库的扩展。 (不是编译器,它们已经通过C ++ 98/03标准编译,但它们被添加为库特性)。
Lambdas是一种新的语言功能,当你真的想在sort
或remove_if
这样的循环不合适的算法中使用1或2行表达时非常有用。
在你的情况下,虽然你可以用lambda编写它,但是如果你的逻辑与你的逻辑一样复杂,你可能不希望在这个例子中使用一个来破坏代码的逻辑。您可能仍然使用lambda来创建一个std :: function。
你甚至可能想要在这里使用多态的更老的“学校”,即传入一个具有签名功能的对象,并将其用作回调。以这种方式维护任何对象的生命周期肯定会更容易。
现在,让我们假设您的对象需要一个callback
函数,该函数基本上在某处获取int
参数并返回一个int。
<强>的std ::结合强>
bind
实际上为函数添加了额外的参数,但该函数必须返回一个int。它可以做的是一个类成员函数或采取额外的参数。
如果是类成员,则需要一个对象来调用它。
std::bind( &MyClass::myFunction, myClassInstance, a, std::placeholders::_1 , b);
myClassInstance
可以是对象类型的引用包装或值传递或指针或std::shared_ptr
或std::unique_ptr
。引用包装器是一个包含引用的特殊类,因为自动模板推导将无法知道您是否确实要传递引用或按值。
小心使用reference-wrappers。在调用函数时,引用必须仍然有效,并且以这种方式发生了许多难以发现的错误。事实上,在早期我拒绝使用绑定和回调,但是很难跟踪这些错误。
placeholders::_1
告诉std::function
将int
参数放在哪里。正如我所说,它可能需要额外的参数,但其中一个将是你的int。基本上它意味着“把你的int值放在这里”。 a
和b
还有其他参数需要传递到此函数并由绑定器提供。
<强> lambda表达式强>
Lambdas确实为你的bind提供了另一种语法,你实际上会在那里调用你的函数调用。我假设,鉴于复杂性,你将在某处编写一个函数和一个类,你只想使用lambda将回调绑定到它。
在这种情况下,你将lambda的方括号放在所谓的“捕获”中。这些就像你绑定的其他参数一样。
std::function< int(int) > myFunc = [ &myClassInstance, a, b ]( int x )
{
return myClassInstance.myFunction( a, x, b );
};
这里的捕获说myClassInstance是一个引用,但另外两个是值。有关捕获语法的信息,请参阅http://en.cppreference.com/w/cpp/language/lambda。