I'm trying to better understand a few fundamental concepts about working with the lambda functions with a vector of objects and std::for_each() loops.
I'm attempting to pass the const int contents of someObjectVector.end()->someObjectVectorMethod() into i, but just can't find a way to make it happen.
I also want to use those iterators to set the parameters of the std::for_each() loop. Is this just not possible, or am I approaching this the wrong way syntactically?
std::for_each(someObjectVector.begin()->someObjectVectorMethod(), (someObjectVector.end()->getSomeObjectVectorData(), [&](int i)
{
someObjectVector[0].setSomeObjectVectorDate() + i;
});
Your syntax is definitely wrong.
As input, std::for_each() expects
a range of elements denoted by 2 input iterators
a unary function object that each element in that range will be passed to as the sole input parameter.
In your code, someObjectVectorMethod() and getSomeObjectVectorData() are not iterators, and your lambda doesn't accept a vector element as input.
What are you TRYING to accomplish with your code? You probably need something more like this instead:
std::vector<YourObjectType> someObjectVector;
...
std::for_each(someObjectVector.begin(), someObjectVector.end(),
[](YourObjectType &obj) {
obj.setSomeObjectVectorData(...);
}
);
Or:
std::vector<YourObjectType*> someObjectVector;
...
std::for_each(someObjectVector.begin(), someObjectVector.end(),
[](YourObjectType *obj) {
obj->setSomeObjectVectorData(...);
}
);
Depending on how someObjectVector is actually declared in your code.
Tweak the above lambdas to suit your actual needs.
Related
I have a member variable of this class that is set<pair<string,map<string,int> > > setLabelsWords; which is a little convoluted but bear with me. In a member function of the same class, I have the following code:
pair<map<string,int>::iterator,bool> ret;
for (auto j:setLabelsWords) {
if (j.first == label) {
for (auto k:words) {
ret = j.second.insert(make_pair(k,1));
if (ret.second == false) {
j.second[k]++;
}
}
}
}
"words" is a set of strings and "label" is a string. So basically it's supposed to insert "k" (a string) and if k is already in the map, it increments the int by 1. The problem is it works until the outermost for loop is over. If I print j.second's size right before the last bracket, it will give me a size I expect like 13, but right outside the last bracket the size goes back to 7, which is what the size of the map is initially before this code block runs. I am super confused why this is happening and any help would be much appreciated.
for (auto j:setLabelsWords) {
This iterates over the container by value. This is the same thing as if you did:
class Whatever { /* something in here */ };
void changeWhatever(Whatever w);
// ...
{
Whatever w;
changewhatever(w);
}
Whatever changewhatever does to w, whatever modifications are made, are made to a copy of w, because it gets passed by value, to the function.
In order to correctly update your container, you must iterate by reference:
for (auto &j:setLabelsWords) {
for (auto j:setLabelsWords) {
This creates a copy of each element. All the operations you perform on j affect that copy, not the original element in setLabelsWords.
Normally, you would just use a reference:
for (auto&& j:setLabelsWords) {
However, due to the nature of a std::set, this won't get you far, because a std::set's elements cannot be modified freely via iterators or references to elements, because that would allow you to create a set with duplicates in it. The compiler will not allow that.
Here's a pragmatic solution: Use a std::vector instead of a std::set:
std::vector<std::pair<std::string, std::map<std::string,int>>> setLabelsWords;
You will then be able to use the reference approach explained above.
If you need std::set's uniqueness and sorting capabilities later on, you can either apply std::sort and/or std::unique on the std::vector, or create a new std::set from the std::vector's elements.
I had pleasure of working with function pointers lately. I got to know how they work. Classical example of function pointers is :
int add() {
return (100+10);
}
int sub() {
return (100-10);
}
void print(int x, int y, int (*func)()) {
printf("value is : %d", (x+y+(*func)()));
}
int main() {
int x=100, y=200;
print(x,y,add);
print(x,y,sub);
}
Somebody asked me the other day that how is it better than calling(inside main):
print(add(x,y));
print(sub(x,y));
and I struggled to explain that. Is it only about the stack or there is something else lying underneath?
I don't really understand why the code you show would be a classical example of function pointers. Functions pointers' utility is much more obvious from code like this:
void transform(int *dst, const int *src, size_t len, int (*f)(int))
{
for (size_t i = 0; i < len; ++i)
dst[i] = f(src[i]);
}
Basically, if you accept a pointer to function as a parameter, it allows you to apply a client-provided operation on data of your choice.
The classic use case (which generalizes) is qsort (https://linux.die.net/man/3/qsort). The sort algorithm is general purpose but the implementation does not know how to compare items because they can be of any type. So you pass in a function that it can call in order to compare two elements.
Function pointers are pretty much useless overhead if you hard coded call the one or the other, like your example. Their power comes from being able to dynamically pick and use them, or pass them to other functions:
You can put function pointers in an array, and loop over them; or you can call a selected one based on a user-input or input file content, or other circumstances. In both cases, they will allow to write code that has a single dynamic call, instead of potential long switch or if statement chains.
The second - and even more useful - concept is to pass them to some other function (also sometimes called 'callbacks'); a classic example is to call qsort with your data table and a custom comparison function in form of a function pointer. qsort will then use your comparison function inside the standardized sort algorithm; there is no other way to implement this.
"pointer to function" is an object. So it can be copied,stored,assigned like any other object.
Where as references to functions (normal functions) are not objects.
I think the classic example is.... User interfaces events handling by using callback functions, which has become an obvious pattern for any UI software.
I have a structure that I want to pass to a function which will sort the struct. However, I don't know how to pass the WHOLE structure.
What I've done is this until now:
void sort_datoteka_sifra(pole &artikli){
}
And I call it like sort_datoteka_sifra(artikli[0]) etc.. but it only passes the [0] elements, I want to pass the whole structure, so that I can use it in the function without having to call artikli[0], artikli[1] and so on in the main function.
You have several options here.
Pass the array as a pointer to its first element as well as the number of elements:
void sort_datoteka_sifra(pole *artikli, int count){
}
If count is static (known at compile time), you can also pass the array by reference:
void sort_datoteka_sifra(pole (&artikli)[100]){
}
If you don't want to hardcode the count, use a function template:
template <int N>
void sort_datoteka_sifra(pole (&artikli)[N]){
}
Use std::vector instead of C-arrays:
void sort_datoteka_sifra(std::vector<pole> &artikli){
}
Use std::sort instead of your custom sort function (#include <algorithms>) and use it with either your existing C-array or (recommended) a std::vector:
std::sort(std::begin(artikli), std::end(artikli));
You have to provide a way to compare two objects; this is done by either overloading operator< or by passing a function (or functor) to the sort algorithm:
bool comparePole(const pole & a, const pole & b) {
return /* condition when you want to have a before b */
}
std::sort(std::begin(artikli), std::end(artikli), &comparePole);
If you don't want to write a function and have C++11, you can use a lambda function:
std::sort(std::begin(artikli), std::end(artikli), [](const pole & a, const pole & b) {
return /* condition when you want to have a before b */
});
If you want to compare the elements by some member (which has a corresponding operator< overload, which is the case for simple types like int, std::string, etc.), use compareByMember from my other answer at https://stackoverflow.com/a/20616119/592323, e.g. let's say pole has an int ID by which you want to sort:
std::sort(std::begin(artikli), std::end(artikli), compareByMember(&pole::ID));
To sort a sub-array of size count, don't use std::end but:
std::sort(std::begin(artikli), std::begin(artikli) + count, &comparePole);
Of course you can combine the third option with one of the first two, i.e. provide a sort function which is implemented in terms of std::sort.
Your function requests a reference to a single element. And you obviously also pass only a single element. So, to pass the complete array, you should use a pointer, if it's an array allocated with new Or a statically allocated array, e.g.
void fun(pole* artikli);
Otherwise for C++, it's common to use std::vector and pass it by reference:
std::vector<pole> artikli;
void fun(std::vector<pole>& artikli);
I am trying to create a jump table for a fuzzy controller. Basically, I have a lot of functions that take in a string and return a float, and I want to be able to do something along the lines:
float Defuzzify(std::string varName, DefuzzificationMethod defuzz)
{
return functions[defuzz](varName);
}
where DefuzzificationMethod is an enum. The objective is to avoid a switch statement and have a O(1) operation.
What I have right now is:
float CenterOfGravity(std::string varName);
std::vector<std::function<float (std::string)>> defuzzifiers;
Then I try to initialize it in the constructor with:
defuzzifiers.reserve(NUMBER_OF_DEFUZZIFICATION_METHODS);
defuzzifiers[DEFUZZ_COG] = std::bind(&CenterOfGravity, std::placeholders::_1);
This is making the compiler throw about 100 errors about enable_if (which I don't use anywhere, so I assume std does). Is there a way to make this compile ? Moreover, is there a way to make this a static vector, since every fuzzy controller will essentially have the same vector ?
Thanks in advance
Reserve just makes sure there's enough capacity, it doesn't actually mak the vector's size big enough. What you want to do is:
// construct a vector of the correct size
std::vector<std::function<float (std::string)>> defuzzifiers(NUMBER_OF_DEFUZZIFICATION_METHODS);
// now assign into it...
// if CentorOfGravity is a free function, just simple = works
defuzzifiers[DEFUZZ_COG] = CenterOfGravity;
// if it's a method
defuzzifiers[DEFUZZ_COG] = std::bind(&ThisType::CenterOfGravity, this, std::placeholders::_1);
Now this might leave you some holes which don't actually have a function defined, so maybe you want to provide a default function of sorts, which the vector constructor allows too
std::vector<std::function<float (std::string)>> defuzzifiers(
NUMBER_OF_DEFUZZIFICATION_METHODS,
[](std::string x) { return 0f; }
);
An unrelated note, you probably want your functions to take strings by const-ref and not by value, as copying strings is expensive.
How to send a portion of a QVector to a function?
QVector<int> a;
a.append(1);
a.append(2);
a.append(3);
a.append(4);
a.append(5);
Some printing function should print "2 3 4" taking the subset of the vector as an argument.
In R this would be possible using a[2:4].
Is this at all possible?
Note: In the std::vector, it is advised to use the insert function to create a new variable. This is a different insert though than QVector has, and thus I cannot find a recommended method.
I must write at least 30 characters so I can tell you, you should try:
a.mid(1,3);
You could always write a function to do this operation for you, e.g.
QVector<int> sub_vector(const QVector<int>& vec, size_t from, size_t to)
{
QVector<int> subvec;
for (size_t i = from; i <= to; ++i)
subvec.append(vec[i]);
return subvec;
}
Yes it is possible, but you must pass a pair of iterators (begin and end of the range you want, you can use std::pair to pass only one argument or use a clearer method that take two QVector::iterator arguments and that way it's clearer that you meant that function to take a range) or if it's simpler to you (or the elements you want are not in continuous order in original QVector) construct another QVector that contains only the selected elements (kind of the solution proposed by john).