I am trying to find an object in a vector of objects whos value of a member variable is true. Could it be done without defining a lamba function or function object, by just specifying the member variable itself:
class A
{
public:
explicit A(bool v, int v2, float v3) : value(v), value2(v2), value3(v3)
{}
...
bool value;
int value2;
float value2;
...
}
int main()
{
std::vector<A> v;
v.push_back(A(false, 1, 1.0));
v.push_back(A(true, 2, 2.0));
v.push_back(A(false, 3, 3.0));
auto iter = std::find_if(v.begin(), v.end(), &A::value);
}
Compiling as is above does not work as it assumes a A* and not A.
Not that its a problem to use lambdas, just curious.
You may use std::mem_fn
auto iter = std::find_if(v.begin(), v.end(), std::mem_fn(&A::value));
Demo
Note that range library should allow directly:
auto iter = range::find_if(v, &A::value);
If you cannot use C++11 lambdas, you can do that with std::bind:
auto iter = std::find_if(v.begin(), v.end(), std::bind(&A::value, std::placeholders::_1));
A solution could be the following
(Optional) Don't mark your constructor A(bool) as explicit to allow implicit conversion from bool to A (live demo on coliru)
Overload operator==() so that it only uses value to establish equality.
You can also supply an operator==(bool v) { return value == v;} (see this demo)
Of course I would advise you not to use that solution as it is quite dirty. Just supply a predicate using std::find_if to do the job. Note that the said predicate must have an operator() so of course you cannot supply a value such as a bool as the predicate to std::find_if
Related
I'm trying to figure out a nice way to find the index of a certain object in a vector - by comparing a string to a member field in the object.
Like this:
find(vector.begin(), vector.end(), [object where obj.getName() == myString])
I have searched without success - maybe I don't fully understand what to look for.
You can use std::find_if with a suitable functor. In this example, a C++11 lambda is used:
std::vector<Type> v = ....;
std::string myString = ....;
auto it = find_if(v.begin(), v.end(), [&myString](const Type& obj) {return obj.getName() == myString;})
if (it != v.end())
{
// found element. it is an iterator to the first matching element.
// if you really need the index, you can also get it:
auto index = std::distance(v.begin(), it);
}
If you have no C++11 lambda support, a functor would work:
struct MatchString
{
MatchString(const std::string& s) : s_(s) {}
bool operator()(const Type& obj) const
{
return obj.getName() == s_;
}
private:
const std::string& s_;
};
Here, MatchString is a type whose instances are callable with a single Type object, and return a boolean. For example,
Type t("Foo"); // assume this means t.getName() is "Foo"
MatchString m("Foo");
bool b = m(t); // b is true
then you can pass an instance to std::find
std::vector<Type>::iterator it = find_if(v.begin(), v.end(), MatchString(myString));
In addition to the Lambda and the handwritten functor used by juancho, you have the possibility to use boost::bind (C++03) or std::bind (C++11) and a simple function:
bool isNameOfObj(const std::string& s, const Type& obj)
{ return obj.getName() == s; }
//...
std::vector<Type>::iterator it = find_if(v.begin(), v.end(),
boost::bind(&isNameOfObj, myString, boost::placeholders::_1));
Or, if Type has a method isName:
std::vector<Type>::iterator it = find_if(v.begin(), v.end(),
boost::bind(&Type::isName, boost::placeholders::_1, myString));
This is just for completeness. In C++11 I'd prefer Lambdas, in C++03 I'd use bind only if the comparison function itself exists already. If not, prefer the functor.
PS: Since C++11 has no polymorphic/templated lambdas, bind still has it's place in C++11, e.g. if the parameter types are unknown, hard to spell, or otherwise not easy to deduce.
A simple iterator may help.
typedef std::vector<MyDataType> MyDataTypeList;
// MyDataType findIt should have been defined and assigned
MyDataTypeList m_MyObjects;
//By this time, the push_back() calls should have happened
MyDataTypeList::iterator itr = m_MyObjects.begin();
while (itr != m_MyObjects.end())
{
if(m_MyObjects[*itr] == findIt) // any other comparator you may want to use
// do what ever you like
}
When I define the custom comparison function inside the class I'll get the error:
'Solution::myfunction': non-standard syntax; use '&' to create a pointer to member
But if I define it outside the class it works. How can I define it inside the class?
class Solution {
public:
bool myfunction(const vector<int> &i, const vector<int> &j) {
return i.front() < j.front());
}
vector<vector<int>> vec;
...
sort(vec.rbegin(), vec.rend(), myfunction);
}
Thanks
Non-static member functions take an implicit this as first parameter. The correct way to call your member function would be
Solution s;
std::vector<int> x;
s.myfunction(x,x);
when you actually want a function that only takes two vectors as parameter. Declare it as static or use a free-function (the prefered way).
PS: Unless you need to call the same comparison function in different scopes, I would suggest to use a lambda:
sort(vec.begin(), vec.end(),
[](const vector<int> &i, const vector<int> &j) {
return i.front()<j.front();
}
);
There are couple way to fix it:
I prefer provide lambda:
sort(vec.rbegin(), vec.rend(), [](const auto &a, const auto &b)
{
return std::lexicographical_compare(a.begin(), a.end(),
b.begin(), b.end());
});
Other way is to provide comparetion class:
class CmpIntVectors {
public:
bool operator(const vector<int> &a, const vector<int> &b) const
{
return std::lexicographical_compare(a.begin(), a.end(),
b.begin(), b.end());
}
};
...
sort(vec.rbegin(), vec.rend(), CmpIntVectors{});
Or make myfunction static.
Disclaimer: I'm assuming that your vec looks like this:
std::vector<std::vector<int>> vec;
Lambdas are the preferred way nowadays instead of defining your own comparison function. They are more readable and in-place, i.e. you can see the code where you call sort() rather than look in some header file elsewhere.
If for some reason you still want to use class member function, then use lambda and pass this to it:
sort(vec.rbegin(), vec.rend(), [this](const vector<int> &i, const vector<int> &j){
return this->myfunction(i, j);
});
I have a vector of objects. My data structure is the following:
class my_class{
float a; int b;
};
my_class obj;
vector<my_class> vec;
The vector vec contains data of the form:
vec
((10.0,2),(100,3),(19.0,3)...)
Now from vector vec I intend to delete the elements which are less than or equal to the last element of vec...For this I am using erase and remove_if functions:
vec.erase(std::remove_if(vec.begin(), vec.end(), predicate_function(vec, (vec.end()-1).a, (vec.end()-1).b)), vec.end());
The predicate_function which I have does an iteration over "vec". However, this defeats the purpose of using std::remove_if. Can someone please help as to what the predicate_function should look like in order for remove_if to work. I dont want to use lambda_function. Also my compiler is GCC
The predicate function will automatically be passed the parameters from each Iterator. So it'd look something like:
bool predicate_function(const my_class& m)
{
//Some logic here
}
Which would then simply be called as:
vec.erase(std::remove_if(vec.begin(), vec.end(), predicate_function), vec.end());
In C++ terms, std::remove_if expects a UnaryPredicate as its 3rd parameter, which is either a function or functor accepting 1 argument and returning bool.
Edit: To do what you want in the comment, you'd need to use a functor (or std::bind, but we'll go the functor route here):
struct compare_last
{
const my_class last_;
compare_last(const my_class& last)
: last_(last)
{ }
bool operator()(const my_class& m) const
{
return m == last_; //Or however you do your comparisons
}
};
my_class& last = *(--vec.end());
vec.erase(std::remove_if(vec.begin(), vec.end(), compare_last(last)), vec.end());
I have:
struct MyStruct
{
char* name;
int* somethingElse;
};
And I need to find in a std::vector<MyStruct*> an element (by using std::find_if) whose name is "XYZ" ... but ... the Predicate of std::find_if (if I have managed to understand it correctly) is a plain function, and it takes in a MyStruct pointer and I have no idea where I can specify the extra "XYZ" value to be used in the comparison.
So, how can I use std::find_if or this purpose? (Obviously, looking for a nice solution, not a global variable, or just walk through the list, ....)
Thanks, f
You can use a functor for this (hope I didn't get anything wrong, as I typed it in the browser):
class finder
{
const char* name;
public:
finder(const char* _name): name(_name) {}
bool operator()(MyStruct* elem) {return strcmp(elem->name, name) == 0;}
};
finder f("sample");
std::find_if(myvector.begin(), myvector.end(), f);
If you use C++11 and lambda:
std::vector<MyStruct> mystructus;
std::find_if(mystructus.begin(), mystructus.end(),
[](const MyStruct& ms){ return ms.name == std::string("XYZ"); } );
You have two options, either use functors or lamdas.
Using functors, you create a new class (or structure) whose constructor takes the string you want to search for, then it has an operator() function that is called by std::find_if:
class my_finder
{
std::string search;
public:
my_finder(const std::string& str)
: search(str)
{}
bool operator()(const MyStruct* my_struct) const
{ return search == my_struct->name; }
};
// ...
std::find_if(std::begin(...), std::end(...), my_finder("XYZ"));
The second using lambdas is less code, but requires recent version of the compiler that can handle C++11 lambdas:
std::find_if(std::begin(...), std::end(...), [](const MyStruct* my_struct)
{ return std::string("XYZ") == my_struct->name; });
The last example can even be generalized further:
using namespace std::placeholders; // For `_1` used below in `std::bind`
// Declare a "finder" function, to find your structure
auto finder = [](const MyStruct* my_struct, const std::string& to_find) {
return to_find == my_struct->name;
};
auto xyz = std::find_if(std::begin(...), std::end(...), std::bind(finder, _1, "XYZ"));
auto abc = std::find_if(std::begin(...), std::end(...), std::bind(finder, _1, "ABC"));
This way the lambda can be reused.
Predicate is anything, that can have operator () applied to it (with the expected argument(s) and returns something convertible to bool). A pointer to function is such thing, but so is an object that defines operator().
You need to provide a predicate like this:
struct Comparator
{
Comparator(const char* find) : m_find(find){}
bool operator()(MyStruct* p) const
{
return strcmp(p->name, m_find) == 0;
}
const char* m_find;
};
Then you can std::find_if like this:
vector<MyStruct*>::iterator iter = std::find_if(vec.begin(), vec.end(), Comparator("XYZ"));
if(iter != vec.end())
{
MyStruct* p = *iter;
}
Or if your compiler supports C++11 you can use lambdas and get rid of the predicate functor:
auto it = std::find_if(vec.begin(), vec.end(), [](MyStruct* p) { return strcmp(p->name, "XYZ") == 0;});
I don't understand why this isn't working. I have a function that returns the result of the std::find method. I read that it returns an iterator to object it finds. But when I try passing the lambda that returns that value it gives me a bunch of errors, why?
void f(std::function<std::vector<int>::iterator()>) {}
int main()
{
std::vector<int> v{0, 1, 2, 3};
auto p = [=] (int n) {
return std::find(v.begin(), v.end(), n);
};
f(p);
}
I get a lot of incomprehensible errors. I even did a type check here and it returned true:
std::is_same<std::vector<int>::iterator, decltype(std::find(v.begin(), v.end(), N))>::value;
// -> true
So why doesn't this work when I pass a function to f with std::function that returns this type?
Assuming the int parameter missing in your std::function parameter was a copy-paste mistake, apparently v.begin() and v.end() return const_iterators rather than normal iterators.
This is due to the fact that your lambda was capturing by value, making your std::vector const(and thus its iterators). Capturing everything by reference works, otherwise, your std::function should return a const_iterator:
#include <vector>
#include <functional>
#include <algorithm>
void f(std::function<std::vector<int>::iterator (int)>) {}
int main()
{
std::vector<int> v{0, 1, 2, 3};
auto p = [&] (int n) {
return std::find(v.begin(), v.end(), n);
};
f(p);
}
As you are capturing by value, the captured vector (and associated iterators) are const by default. If you want it to be mutable, you need to change the lambda:
auto p = [=] (int n) mutable {
return std::find(v.begin(), v.end(), n);
};
Because f expects a function that takes no arguments, but your lambda has one int parameter.