The link looks complete but it's very complicated for me. Some simpler explanation could help better. Moreover, I think the idea is a shade risky. I prefer no to take that risk and use this instead: Less_than<string> Lt{ "bakur"};
The second question: I guess I know how to use functors and also know they're useful and any programmer must make use of them if needed, but what I don't know is that how they're useful! A "simple" illustration/example which demonstrates the usefulness of functors so that I can get the whole idea and can have that in mind to use wherever it's good, will be very valuable for me. :)
template <typename It, typename F>
void map(It begin, It end, F &&f){
for (auto i = begin; i != end; ++i)
*i = f(*i);
}
template <typename T>
struct AddOne{
T operator()(T &x) const{
return x + 1;
}
};
template <typename T>
struct AddX{
T state = {};
T operator()(const T &x){
return x + ++state;
}
};
std::vector<int> values(10);
map(values.begin(), values.end(), AddOne<int>());
map(values.begin(), values.end(), AddX<int>());
Note that in modern C++ lambdas replace functors in most use cases. You should only use functors if the encapsulated behavior is too complex to express succinctly in a few lines.
1 2 3
map(values.begin(), values.end(), [](constauto &x){ return x + 1});
int state = 0;
map(values.begin(), values.end(), [&state](constauto &x){ return x + ++state});
I really can't understand this code. It's very complex for one who is trying to get familiar with functors properly by an example.
The code might be perfect and thanks for that, but not useful for me. :(
What I need is a simpler example (or a pair of examples, one using a functor and the other not) to show me when and why I should make use of this cpp facility appropriately.
But I learnt two things from your code: the rvalue reference, and that using lambdas we may rarely need functors. :)
I must say, that site is fantastic. It's probably the best learning website for getting started with a new technology and getting through its challenges by reading its friendly and simple written contents. Thanks, :)
But I'm not completely sure I found the answer I was looking for. I mean, I know where and when to use a class, template, function, container, and more things, but it's not very evident where and when in the code I'm working on I should pick out a functor.
I know where and when to use a class, template, function,
A function is a functor. Its exactly the same, even if your 'function' happens to be a class that overloaded () to act that way. Why would you make such a thing from a class? I do not use that often, but its there if you need it. You can use it for some cool wrappers -- say you have a function that needs to access private class members of a class that you are not going to tamper with for whatever reasons. You can inherit into a new class, access these items directly, and make it look like a function. There are other uses too, but that is a simple one. Of course if the original had a getter on everything, you would not need this, but not every class has a getter for every private variable. Its the kind of thing to keep in the back of your mind, knowing that it exists, and once in a while you may find a use for it.
template <typename It, typename F>
void map(It begin, It end, F &&f){
for (auto i = begin; i != end; ++i)
*i = f(*i);
}
template <typename T>
struct AddOne{
T operator()(T &x) const{
return x + 1;
}
};
template <typename T>
struct AddX{
T state = {};
T operator()(const T &x){
return x + ++state;
}
};
std::vector<int> values(10);
map(values.begin(), values.end(), AddOne<int>());
map(values.begin(), values.end(), AddX<int>());
My first question is about AddOne<int>() on line 23 which will be sent to F &&f on line 2.
AddOne is a generic struct. Its type now is int. Is AddOne<int>() a temporary object with the value 0, as the initial value for the int type, sent firstly to its struct returning the value (0+1) to be sent to f on line 2? f there is an rvalue reference, so needs a value. Right, please?
AddOne is a generic struct. Its type now is int. Is AddOne<int>() a temporary object with the value 0, as the initial value for the int type
No.
1. AddOne<T> is a template class.
2. T is a type template parameter.
3. On line 23, the type of the template parameter in that particular instantiation of the template is int.
4. Types don't have values. Objects have values. Look at the definition of AddOne<T> and its instantiation:
1 2 3 4 5 6 7
template <typename T>
struct AddOne{
T operator()(T &x) const{
return x + 1;
}
};
AddOne<int>
There are no objects to have values nor are there any zeroes there.
sent firstly to its struct returning the value (0+1) to be sent to f on line 2?
No, completely wrong. Honestly, I don't understand how you got it so wrong, having written functors previously. The overload returns its parameter added to 1 and doesn't use the state of the object at all (which doesn't have any anyway). It's equivalent to
1 2 3 4
template <typename T>
T AddOne(const T &x){
return x + 1;
}
Line 23 creates a temporary unnamed object that has type AddOne<int>. That type has no member variables and thus no "value stored in it".
The function map() has parameter 'f'. The f is initialized on the function call, like you had written: AddOne<int> f( AddOne<int>() );
In fact, since the temporary was default constructed and f is move constructed, the overall result is same as in: AddOne<int> f;
@keskiverto
OK, that temporary unnamed object will be sent to f in the map function, which is an rvalue reference, so needs a rvalue: 0, 1, 2, etc. Right? Then what is that rvalue that f is containing?
OK. So when the first call to map on line 23 is finished, all 10 values of the vector are 1.
And for the second call of map, when the other temporary unnamed object is created by AddX<int>() on line 24, the value of state on line 16 becomes 0, as the initial value for the objects of type int. Right? It's the state of the functor.
Then, on line 4 when the functor of AddX is called, first the state will be incremented, next added to the first value, 1, yielding 2 for the first item in the vector, and so on: 2, 3, 4, 5, 6, 7, 8, 9, 10, 11.