简体   繁体   English

创建一个带有状态的C ++ 11 std :: function <>

[英]Creating a C++11 std::function<> with state

what is the best way to create a C++11 std::function<> with state? 用状态创建C ++ 11 std::function<>的最佳方法是什么?

In plain C++98, I would create a functor struct that inherited from std::unary_function<> or std::binary_function<> . 在纯C ++ 98中,我将创建一个从std::unary_function<>std::binary_function<>继承的函子结构。 So given the following functor, how do I create a std::function<int(int)> from the following functor? 因此,给定以下函子,如何从以下函子创建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);
}

Note that the code above is a great simplification of what I need. 请注意,上面的代码是我需要的极大简化。 Actually, the functor is configured with multiple parameters and reads data from a file (where each record is more complex than an int). 实际上,函子配置了多个参数,并从文件中读取数据(每个记录比int更为复杂)。 Is there a solution that is closer to using functors than using lambdas? 有没有比使用lambda更接近使用函子的解决方案?

Edit : Clarification 编辑 :澄清

Easiest to use a lambda expression for this: 为此最容易使用lambda表达式:

std::function<int(int)> f = [](int n) { return n + 30; }

You can also use std::bind : 您也可以使用std::bind

std::function<int(int)> f = std::bind(std::plus<int>, std::placeholders::_1, 30);

In both cases, the 30 is just an example that could be replaced by a captured variable (make sure to change the capture specification in the lambda to [=] , though), and you would be better off using type auto to avoid a potentially expensive creation of a function object when you only need some callable type. 在这两种情况下, 30都只是一个示例,可以用捕获的变量代替(不过,请确保将lambda中的捕获规范更改为[=] ),并且最好还是使用auto类型来避免潜在的当只需要一些可调用类型时,创建function对象的开销很大。

Use Lambdas: 使用Lambda:

 int x = 0;
 std::function<int (int)> add = [x](int val) { return  x + val; }
 auto add2 = [x](int val) { return  x + val; }

Here, the variables the lambda has access to are in the square brackets. 在此,lambda可以访问的变量在方括号中。 x is passed as a copy. x作为副本传递。 You can also pass a state as a reference by prefixing it with an '&' and capture 'this' 您还可以通过在状态前面加上“&”并捕获“ this”来将状态作为参考

You can continue to use functors and classes in C++11, and in fact std::bind and std::function are now part of the C++11 standard, whereas previously they were part of the boost library and supported in tr1 or as extensions by various standard libraries. 您可以继续在C ++ 11中使用函子和类,实际上std::bindstd::function现在已成为C ++ 11标准的一部分,而以前它们是boost库的一部分并在tr1中受支持或作为各种标准库的扩展。 (Not compilers, they compiled already by the C++98/03 standard, but they were added as a library feature). (不是编译器,它们已经按照C ++ 98/03标准进行了编译,但是它们是作为库功能添加的)。

Lambdas are a new language feature, which are very useful when you really want a 1 or 2 line expression in an algorithm like sort or remove_if where a loop is inappropriate. Lambdas是一种新的语言功能,当您确实希望在不适合循环的sortremove_if sort的算法中真正需要1行或2行表达式时,Lambda非常有用。

In your case, whilst you can write it with a lambda, if your logic is as complex as you make out, you probably don't want to use one in this instance for the sake of breaking up the logic of your code. 在您的情况下,虽然您可以使用lambda进行编写,但如果您的逻辑像您所看到的那样复杂,那么在这种情况下,您可能不想使用一个来破坏代码的逻辑。 You might still use a lambda to create a std::function out of this. 您可能仍然可以使用lambda来创建std :: function。

You might possibly even want to go down the even older "school" of using polymorphism here, ie passing in an object that has a function with a signature, and use that as the callback. 您甚至可能想放弃使用多态性的更古老的“学问”,即传入具有签名功能的对象,并将其用作回调。 It will certainly be easier to maintain the lifetimes of any objects this way. 这样肯定会更容易维护任何对象的生存期。

Now, let's assume your object wants a callback function which essentially takes an int parameter somewhere and returns an int. 现在,让我们假设您的对象需要一个callback函数,该函数实际上在某处接受一个int参数并返回一个int。

std::bind std :: bind

What bind does is actually add extra parameters to a function, but that function must return an int. bind实际上是向函数添加了额外的参数,但是该函数必须返回一个int值。 What it can do is be a class member function or take extra parameters. 它可以做的是成为类成员函数或采用额外的参数。

If it is a class member you need an object to call it on. 如果它是类成员,则需要一个对象来调用它。

std::bind( &MyClass::myFunction, myClassInstance, a, std::placeholders::_1 , b);

myClassInstance can be a reference-wrapper or pass-by-value or a pointer or a std::shared_ptr or std::unique_ptr of an object to your type. myClassInstance可以是引用包装器或传递值,也可以是类型的对象的指针或std::shared_ptrstd::unique_ptr A reference-wrapper is a special class that contains a reference due to the fact that automatic template deduction will not be able to know whether you actually want to be passing a reference or by-value. reference-wrapper是一个包含引用的特殊类,因为自动模板推导将无法知道您实际上是要传递引用还是按值。 Be careful of using reference-wrappers. 使用参考包装器时要小心。 The reference must still be valid at the point the function is called, and many hard-to-find bugs have occurred this way. 该引用在函数调用时必须仍然有效,并且这种方式已经发生了许多难以发现的错误。 In fact in its early days I rejected using bind and callbacks but it was so hard to trace bugs like these. 实际上,在早期,我拒绝使用bind和callbacks,但是很难跟踪此类错误。

The placeholders::_1 tells the std::function where to put the int parameter it is passing. placeholders::_1告诉std::function将传递的int参数放在何处。 As I said, it can take extra parameters, but one of them will be your int. 如我所说,它可以接受额外的参数,但是其中一个将是您的int。 Essentially it means "put your int value here". 本质上,它的意思是“将您的int值放在这里”。 a and b there are other parameters that need to be passed into this function and are supplied by the binder. ab还有其他参数需要传递到此函数中,并由活页夹提供。

Lambdas Lambdas

Lambdas do provide an alternative syntax to your bind in that you will actually invoke the call to your function in there. Lambda确实为绑定提供了另一种语法,因为您实际上将在其中调用对函数的调用。 I am assuming that, given the complexity, you are going to write a function and a class somewhere and you just want to use a lambda to bind the callback to it. 我假设,鉴于复杂性,您将在某个地方编写一个函数和一个类,而您只想使用lambda将回调绑定到它。

In that case, you put in the square brackets of your lambda what is known as its "captures". 在这种情况下,您可以在lambda的方括号中放入所谓的“捕获”。 These are like the other parameters of your bind. 这些就像绑定的其他参数一样。

std::function< int(int) > myFunc = [ &myClassInstance, a, b ]( int x )
{
    return myClassInstance.myFunction( a, x, b );
};

The captures here say that myClassInstance is a reference but the other two are by value. 这里的捕获说myClassInstance是一个引用,而其他两个是按值。 See http://en.cppreference.com/w/cpp/language/lambda for information about capture syntax. 有关捕获语法的信息,请参见http://en.cppreference.com/w/cpp/language/lambda

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM