I'm converting this function to use std::tuple which does not have first and second memebers like std:pair.
std::type_index argumentType(const std::string& name) const
{
return std::find_if(args_.begin(), args_.end(),
[&name](std::pair<std::string, std::type_index> arg)->bool
{
return arg.first == name;
}
)->second;
}
I'm confused by the syntax ->second, what is this doing? and is thre equivalent std::get<1>(arg)
std::type_index argType(const std::string& name) const
{
return std::find_if(args_.begin(), args_.end(),
[&name](std::tuple<std::string, std::type_index, Attribute> arg)->bool
{
return std::get<0>(arg) == name;
}
)std::get<1>(arg);
Example 2:
std::pair
bool hasArg(const std::string& name) const
{
return std::find_if(args_.begin(), args_.end(),
[&name](std::pair<std::string, std::type_index> arg)->bool
{
return arg.first == name;
}
) != args_.end();
}
std::tuple
bool hasArg(const std::string& name) const
{
return std::get<0>(*std::find_if(args_.begin(), args_.end(),
[&name](std::tuple<std::string, std::type_index, Attribute> arg)->bool
{
return std::get<0>(arg) == name;
}
)) != args_.end();
}
std::find_if returns an iterator to a pair, that's why you need to use the arrow operator ->, which the iterator has overloaded to return a reference to the actual value for purposes of member access.
Yes, std::get<1> for a tuple will do pretty much the same, but the syntax will be different:
auto it = std::find_if(...);
return std::get<1>(*it);
You need to use the dereference operator * instead of the arrow operator, because std::get is a free function and not a tuple's member.
Checkout documentation of std::find_if
So std::find_if will return iterator. In code #1 it was iterator to pair, so ->second will husk second element of std::pair. You use -> overloaded operator for iterator.
Example:
auto it = std::find_if(args_.begin(), args_.end(),...);
if(it != args_.end()) // This is important to NOT dereference iterator if it is pointing to end
{
// also you can write (*it).second; (first use dereference operator)
return it->second;
}
// ...
So in you case you should refactor it to:
std::type_index argType(const std::string& name) const
{
// Please don't do so much in 1 line. Compiler will optimize this for you :)
// Please check for std::end, this is potential dangerous.
return std::get<1>(*std::find_if(args_.begin(), args_.end(),
[&name](std::tuple<std::string, std::type_index, Attribute> arg)->bool
{
return std::get<0>(arg) == name;
}
));
}
Same example:
auto it = std::find_if(args_.begin(), args_.end(),...);
if(it != args_.end()) // This is important to NOT dereference iterator if it is pointing to end
{
return std::get<1>(*it);
}
// ...
Important
Please also consider case when you don't find your element. std::find_if will return std::end(args_) if element you are looking for doesn't exist. So calling ->second or std::get<1>(*it) is undefinied behaviour and can crush.
Fix for hasArg function. Now you don't need dereference your iterator.
bool hasArg(const std::string& name) const
{
return std::find_if(std::begin(args_), std::end(args_),
[&name](const std::tuple<std::string, std::type_index, Attribute>& arg)->bool
{
return std::get<0>(arg) == name;
}
) != std::end(args_);
}
In this solution I used std::begin and std::end. This is more uniwersal way instead calling arg_.begin() :)
Please check how I ficed syntax of your second example.
One last thing, when you use std::find_if and lambda to find what you are looking for, argument should be const& in most cases :), because we don't want to make a copy here.
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
}
I have a function which return value if a key exist in map like:
map<int,string> mymap;
//Assume there are some key value pair in above map
string & ReturnKey(int &a)
{
string ret;
map<int,string>::iterator iter = mymap.find(a);
if(iter not_eq mymap.end())
{
ret = iter->second;//I think this will make copy
}
else
return ret;
}
How can I avoid copy of string which is returning from above function?
If you're okay with the returned reference being const, you can do something like this:
const string & ReturnKey(int a)
{
static const string defaultValue; // to be returned if object isn't found
map<int,string>::iterator iter = mymap.find(a);
if(iter != mymap.end())
{
return iter->second;
}
else return defaultValue;
}
It's safe to return a reference to (defaultValue) in the not-found case because defaultValue is declared static and therefore will still exist after the function returns. In the value-found case, the caller will need to be careful not to hold the reference and try to use it after mymap has been cleared or modified, but that's usually not an issue in practice.
You can return a reference to an existing string or raise an exception if it doesn't exist. This is easily done with the std::map::at method:
string& ReturnKey(int a)
{
return mymap.at(a);
}
If you are stuck with a pre-C++11 compiler, you have to do it by hand:
string& ReturnKey(int a)
{
map<int,string>::iterator iter = mymap.find(a);
if(iter == mymap.end())
throw std::out_of_range("Invalid key");
return iter->second;
}
As in your program you can not return the reference of the variable declared inside the function because as the function complete the execution all the variable declared inside that function will get released and deleted.
So in that case you will get null or garbage value every time the function will called.
For this In my opinion you can pass your string argument as a reference in the function.
so, by using this you can get your desired value in your variable.
Or
You can also change the return type of the function to std::string.
I think You have to use this function as:
map<int,string> mymap;
//Assume there are some key value pair in above map
void ReturnKey(int &a, string& str)
{
map<int,string>::iterator iter = mymap.find(a);
if(iter not_eq mymap.end())
{
str = itr->second;
}
}
Or you can return std::string values for status of your operation.
As follows:
map<int,string> mymap;
//Assume there are some key value pair in above map
std::string ReturnKey(int &a)
{
std::string ret;
map<int,string>::iterator iter = mymap.find(a);
if(iter not_eq mymap.end())
{
ret = iter->second;//I think this will make copy
}
else{
delete ret;
return null;
}
return ret;
}
and #include <string> should be used.
Hope this will help you.
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'm very new to c++ and I'm trying to find a way to search a vector of structs for a struct with a certain member data.
I know this would work with simple types in the vector
std::find(vector.begin(), vector.end(), item) != vector.end()
But lets say I have a struct like this:
struct Friend
{
string name;
string number;
string ID;
};
and a vector like this:
vector<Friend> friends;
Then the vector is filled with friends.
Let's say I want to search for a friend with a certain ID, and cout the details. Or delete the certain struct from the vector. Is there a simple way to do this?
This can be done with std::find_if and a search predicate, which can be expressed as a lambda function if you have C++11 (or C++0x) available:
auto pred = [](const Friend & item) {
return item.ID == 42;
};
std::find_if(std::begin(friends), std::end(friends), pred) != std::end(friends);
To use an ID given as a variable, you have to capture it in the lambda expression (within the [...]):
auto pred = [id](const Friend & item) {
return item.ID == id;
};
std::find_if(std::begin(friends), std::end(friends), pred) != std::end(friends);
If you don't have C++11 available, you have to define the predicate as a functor (function object). Remy Lebeau's answer uses this approach.
To remove elements matching the criteria as defined by the predicate, use remove_if instead of find_if (the rest of the syntax is the same).
For more algorithms, see the STL <algorithm> reference.
Use std::find_if(). #leemes and #AndyProwl showed you how to use it in a C++11 compiler. But if you are not using a C++11 compiler, then you can use it like this instead, which defines a functor comparing the ID of a given item with a previously specified ID in its constructor:
class MatchesID
{
std::string _ID;
public:
MatchesID(const std::string &ID) : _ID(ID) {}
bool operator()(const Friend &item) const
{
return item.ID == _ID;
}
};
std::find_if(vector.begin(), vector.end(), MatchesID("TheIDHere")) != vector.end();
If you have other classes in your project which use IDs, you can make this functor templated:
template<typename IDType>
class MatchesID
{
IDType _ID;
public:
MatchesID(const IDType &ID) : _ID(ID) {}
template<class ItemType>
bool operator()(const ItemType &item) const
{
return item.ID == _ID;
}
};
std::find_if(vector.begin(), vector.end(), MatchesID<std::string>("TheIDHere")) != vector.end();
You can use std::find_if in combination with functors (if you are working with C++98) or lambdas (if you are using C++11, which I will assume):
using namespace std;
int ID = 3; // Let's say...
auto it = find_if(begin(vector), end(vector), [=] (Friend const& f) {
return (f.ID == ID);
});
bool found = (it != end(vector));
If you want to find an element in STL container, use std::find or std::find_if algorithms
With C++03, you need to overload operator== for std::find
bool operator==(const Friend& lhs, const Friend& rhs)
{
return lhs.ID == rhs.ID;
}
if (std::find(friends.begin(), friends.end(), item) != friends.end())
{
// find your friend
}
OR C++11 with lambda:
std::find_if(friends.begin(), friends.end(), [](Friend& f){ return f.ID == "1"; } );
If you want to remove a certain element, use std::remove_if
std::remove_if(friends.begin(), friends.end(),
[](Friend& f){ return f.ID == "1"; });
I am trying to understand how to find an item in a list of pointers in C++, using std::find
If I had for example:
std::list<string> words;
std::string word_to_be_found;
I could just search like this:
std::list<string>::iterator matching_iter = std::find(words,begin(), words.end(), word_to_be_found)
but what if I have a lsit of pointers?
std::list<string *> words;
the above syntax will not work anymore. Can I do it some similar way?
thanks!
You can pass a predicate to the std::find_if function:
bool pointee_is_equal(const std::string& s, const std::string* p) {
return s == *p;
}
// ...
std::list<string>::iterator matching_iter =
std::find_if(words,begin(), words.end(),
std::bind1st(pointee_is_equal, word_to_be_found));
In C++11 this becomes much easier, thanks to lambdas:
auto matching_iter = std::find_if(words,begin(), words.end(),
[&word_to_be_found](const std::string* p) {
return word_to_be_found == *p;
});
Provide your own predicate:
struct comparator
{
bool operator()(std::string const* item)
{
return toFind == *item;
}
std::string toFind;
};
comparator cinst = { word_to_find };
std::list<string*>::iterator matching_iter = std::find_if(words,begin(), words.end(), cinst)
You want to use std::find_if() instead, and supply it a functor to do the comparisons.