创建C ++ 11 std :: function<>与国家

时间:2013-12-12 09:57:41

标签: c++

用状态创建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更接近使用仿函数的解决方案?

修改:澄清

3 个答案:

答案 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::bindstd::function现在是C ++ 11标准的一部分,而之前它们是升级的一部分库,并在tr1中支持或作为各种标准库的扩展。 (不是编译器,它们已经通过C ++ 98/03标准编译,但它们被添加为库特性)。

Lambdas是一种新的语言功能,当你真的想在sortremove_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_ptrstd::unique_ptr。引用包装器是一个包含引用的特殊类,因为自动模板推导将无法知道您是否确实要传递引用或按值。 小心使用reference-wrappers。在调用函数时,引用必须仍然有效,并且以这种方式发生了许多难以发现的错误。事实上,在早期我拒绝使用绑定和回调,但是很难跟踪这些错误。

placeholders::_1告诉std::functionint参数放在哪里。正如我所说,它可能需要额外的参数,但其中一个将是你的int。基本上它意味着“把你的int值放在这里”。 ab还有其他参数需要传递到此函数并由绑定器提供。

<强> 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