In the 1st code snippet below, I am trying to remove an element from a vector within a member function based on a static condition function fed into std::remove_if function. My problem here is that the input parameter uuid in removeVipAddress method cannot accessed within the condition function. What do you think I should do here to enable removal of an item from the vector based on the input parameter named uuid? Thanks. NOte: This is a follow up problem explained previously in Removing an item from an std:: vector
SNIPPET 1 (CODE)
void removeVipAddress(std::string &uuid)
{
struct RemoveCond
{
static bool condition(const VipAddressEntity & o)
{
return o.getUUID() == uuid;
}
};
std::vector<VipAddressEntity>::iterator last =
std::remove_if(
mVipAddressList.begin(),
mVipAddressList.end(),
RemoveCond::condition);
mVipAddressList.erase(last, mVipAddressList.end());
}
SNIPPET 2 (COMPILATION OUTPUT)
$ g++ -g -c -std=c++11 -Wall Entity.hpp
Entity.hpp: In static member function ‘static bool ECLBCP::VipAddressSet::removeVipAddress(std::string&)::RemoveCond::condition(const ECLBCP::VipAddressEntity&)’:
Entity.hpp:203:32: error: use of parameter from containing function
Entity.hpp:197:7: error: ‘std::string& uuid’ declared here
If you're using C++11 this could be done with a lambda:
auto last = std::remove_if(
mVipAddressList.begin(),
mVipAddressList.end(),
[uuid]( const VipAddressEntity& o ){
return o.getUUID() == uuid;
});
The last parameter on that function call declares a lambda, which is an anonymous inline function. The [uuid] bit tells it to include uuid in the scope of the lambda.
There's a tutorial on lambdas here
Alternatively you probably want to provide a constructor & member function to your RemoveCond predicate (and implement it using operator() rather than a function named condition).
Something like this:
struct RemoveCond
{
RemoveCond( const std::string& uuid ) :
m_uuid( uuid )
{
}
bool operator()(const VipAddressEntity & o)
{
return o.getUUID() == m_uuid;
}
const std::string& m_uuid;
};
std::remove_if(
mVipAddressList.begin(),
mVipAddressList.end(),
RemoveCond( uuid );
);
If you don't have C++11 lambdas, you could express your RemoveCond as a functor:
struct RemoveCond
{
RemoveCond(const std::string uuid) : uuid_(uuid) {}
bool operator()(const VipAddressEntity & o) const
{
return o.getUUID() == uuid_;
}
const std::string& uuid_;
};
then pass an instance to std::remove_if:
std::remove_if(mVipAddressList.begin(),
mVipAddressList.end(),
RemoveCond(uuid));
BTW you removeVipAddress function should take a const reference:
void removeVipAddress(const std::string &uuid)
Related
I am working on a program that have an struct based list that stores some file attributes data.
struct files {
string name;
string size;
string owner;
};
And the list variable is described below
list<files> myfilecollection;
The thing that I want to do is to check if some determined file name is contained within the myfilecollection. Basically I checked this example post and tried to write this function:
bool isFileSensible(const string& filename)
{
auto match = std::find_if(myfilecollection.cbegin(), myfilecollection.cend(), [name] (const files& s) {
return s.name == filename;
});
return match != myfilecollection.cend();
}
This implementation works all right with the GCC 9.2.0 but I need to make this function work on the GCC 4.4.4 with are not even C++ 11 compliant. What is the best way to re-implement this function for the GCC 4.4.0?
Best regards,
F.Borges
A lambda is nothing more then a short form for writing a functor. You can just revert back to writing a functor that behaves the same way like
bool isFileSensible(const string& filename)
{
struct FindFilename
{
std::string filename;
FindFilename(std::string filename) : filename(filename) {}
bool operator()(const files& obj)
{
return obj.name == filename;
}
};
std::list<files>::const_iterator match = std::find_if(myfilecollection.cbegin(), myfilecollection.cend(), FindFilename(filename));
return match != myfilecollection.cend();
}
I've put FindFilename in the scope of the function so it does not pollute the global namespace. If you want to reuse this functor elsewhere you can move it out into the global scope.
You are using auto and a lambda, which are both C++11. Luckily in your case, both can be replaced trivially.
Lambdas are basically just syntactic sugar for functor classes, so you can use instead:
struct compare_files_by_name {
std::string target;
compare_files_by_name(const std::string& target) : target(target) {}
bool operator()(const files& f) {
return f.name == target;
}
};
And what find_if returns is a list<files>::const_iterator. If we put that together you get:
bool isFileSensible(const string& filename)
{
compare_files_by_name comp(filename);
std::list<files>::const_iterator match = std::find_if(myfilecollection.cbegin(), myfilecollection.cend(),comp);
return match != myfilecollection.cend();
}
PS: Being used to auto, I find it strange to fully write out an iterator type. I would probably write it as
return myfilecollection.cend() != std::find_if(....
simply to avoid spelling out the iterator type.
I've implemented a list and iterator templates, the find method is supposed to receive a functor so I declared and implemented one but I keep getting the error that there's no such an object!
"no matching function for call to object of type const findBond "
here's the implementation of the find method:
template <class T>
template <class Predicate>
Iterator<T> List<T> :: find(const Predicate &predicate) {
for (Iterator<T> iterator=begin(); iterator != end(); ++iterator) {
if (predicate(*iterator)) {
return iterator;
}
}
return end();
}
// predicate is a functor that is supposed to return a boolean value
here's the function object:
class findBond{
Bond& bond;
public:
findBond( Bond& bond1) : bond(bond1) {}
bool operator() (Bond& bond1){
return bond==bond1;
}
};
I'm trying to use them here:
void InvestmentBroker :: addBond(const string& name, double value, int amount ){
Bond bond = *new Bond(name, value, amount);
if (bondsDatabase.find(findBond(bond)) != bondsDatabase.end()) {
//throw an exception
} else {
// insert bond to dataBase
}
}
I included the needed files so it's not about the includes
What's wrong? What am I missing here?
Your find method takes a const Predicate& as its argument. That means you can only call const methods of the predicate. However, your functor's call operator is not declared const. You can fix your problem by declaring it const like this:
bool operator() (Bond& bond1) const {/* do stuff */ }
That const at the end of the declaration means that you can't modify this from within the function, which in turn means you can call the function on a const object.
It looks like a constness issue to me - findBond should be const on most arguments.
Change findBond to this
class findBond{
const Bond& bond;
public:
findBond( const Bond& bond1) : bond(bond1) {}
bool operator() const ( const Bond& bond1){
return bond==bond1;
}
};
Can somebody explain or help me why this isnt working?
std::vector<std::shared_ptr<Publication> > Bibliography::givePubWithIFHigherThan(float value) const
{
Publication *p;
std::vector<std::shared_ptr<Publication>> highIFPubs(publications);
auto checkIF = std::mem_fun(p->IFHigherThan(value));
auto last = std::copy_if(publications.begin(), publications.end, highIFPubs.begin(),
[=] (std::shared_ptr<Publication> p)
{
return checkIF(*p, value);
});
return highIFPubs;
}
class Publication
{
public:
Publication(std::string aTitle, int aYear, std::string anID);
virtual bool IFHigherThan(float value) const {return false;};
private:
};
class Paper : public Publication
{
public:
Paper(std::string aTitle, int aYear, std::string aJournal, float aImpactFactor);
bool IFHigherThan(float value) const {return value < impactFactor;};
private:
};
At the moment i get this error,
no matching function for call to 'mem_fun(bool)'
auto checkIF = std::mem_fun(p->IFHigherThan(value));
^
std::mem_fun is a depracated helper function that will probably be soon removed from the standard library. std::mem_fn would be a better choice.
Moreover, if you want to use std::mem_fn, std::mem_fun or std::bind with a function, then you pass in a pointer to function, not a call expression, so instead of:
auto checkIF = std::mem_fun(p->IFHigherThan(value));
use:
auto checkIF = std::mem_fn(&Publication::IFHigherThan);
Alternatively, don't use any wrapper, just directly call the selected member function:
auto last = std::copy_if(publications.begin(), publications.end(), highIFPubs.begin(),
[=] (std::shared_ptr<Publication> p)
{
return p->IFHigherThan(value);
});
There is one more logical error you have in your code:
std::vector<std::shared_ptr<Publication>> highIFPubs(publications.size());
should be:
std::vector<std::shared_ptr<Publication>> highIFPubs;
and then instead of:
auto last = std::copy_if(publications.begin(), publications.end()
, highIFPubs.begin(),
// ~~~~~~~~~~~~~~~~~^
you should be using std::back_inserter:
auto last = std::copy_if(publications.begin(), publications.end()
, std::back_inserter(highIFPubs),
// ~~~~~~~~~~~~~~~~~^
as you don't actually know how many elements will the resultant vector have.
Let's see a real life example:
class RuleNameConverter {
public:
RuleNameConverter(const boost::property_tree::ptree& pt);
int toIdentifier(const std::string& name) const;
std::string toName(const int id) const;
private:
using Bimap = boost::bimap<std::string, int>;
Bimap bimap_;
};
Where the constructor is this:
RuleNameConverter::RuleNameConverter(const boost::property_tree::ptree& pt) {
for (const auto& item : pt) {
if (item.first == "rule") {
auto name = item.second.get < std::string > ("<xmlattr>.name");
auto id = item.second.get<int>("<xmlattr>.id");
bimap_.insert(Bimap::value_type { name, id });
}
}
}
Assume you want a const member attribute:
...
const Bimap bimap_;
};
You must initialize it in the initializer list, not in the constructor body. It's initialization is non trivial, so you must delegate a function to compute its value. You can use the value returned by a lambda, taking advantages of the move semantics (no copy of temporary objects):
RuleNameConverter::RuleNameConverter(const boost::property_tree::ptree& pt) :
bimap_ { [&pt]() {
Bimap results;
for (const auto& item : pt) {
if (item.first == "rule") {
auto name = item.second.get < std::string > ("<xmlattr>.name");
auto id = item.second.get<int>("<xmlattr>.id");
results.insert(Bimap::value_type {name, id});
}
}
return results;
}() } {
}
Are there any drawbacks to using this technique? Is it worth the trouble? I find it slightly less readable, but what about performance?
Performance-wise, it should not matter all that much. You don't copy around any Bitmap objects, and the construction of your lambda should not take any noticeable time.
But for readability, I would create a static member function instead of a lambda here:
class RuleNameConverter {
public:
RuleNameConverter(const boost::property_tree::ptree& pt);
private:
static Bitmap createBitmap(const boost::property_tree::ptree& pt);
};
RuleNameConverter::RuleNameConverter(const boost::property_tree::ptree& pt) :
bimap_ { createBitmap(pt) } {
}
Bitmap RuleNameConverter::createBitmap(const boost::property_tree::ptree& pt) {
Bimap results;
for (const auto& item : pt) {
if (item.first == "rule") {
auto name = item.second.get < std::string > ("<xmlattr>.name");
auto id = item.second.get<int>("<xmlattr>.id");
results.insert(Bimap::value_type {name, id});
}
}
return results;
}
When you need to initialise several members using helper functions, creating a new lambda for each member leads to an unmaintainable mess in the constructor initialiser list, but several helper functions don't need to have that problem. Additionally, if you add constructor overloads, createBitmap can be easily called from multiple constructors.
Alternatively, use a regular non-member function if the body of createBitmap is not really specific to your RuleNameConverter.
You could wrap the Bimap in another class, where its constructor would have the exact same body as the lambda.
I can't see how using a lambda to avoid a superficial class in this case would lead to any problems, except its intent is perhaps less clear, because it doesn't have a name (but that's the case with pretty much any lambda).
So I want to create a simple map std::map<T1, std::string> and I have a function that returns std::string I want somehow to link item creation in std::map with my function so that when my_map[some_new_element] is called my function will be called and its return set to value for some_new_element key. Is such thing possible and how to do it?
You can wrap the map itself or the value type or operator[].
Last wrapper will be the simplest:
template <typename T>
std::string& get_default(std::map<T, std::string>& map, const T& key) {
auto it = map.find(key);
if (it == map.end()) {
return map[key] = create_default_value();
} else {
return *it;
}
}
The value type shouldn't be too hard, either:
struct default_string {
std::string wrapped_string;
default_string() : wrapped_string(create_default_value()) {}
explicit default_string(const std::string& wrapped_string)
: wrapped_string(wrapped_string) {}
operator const std::string&() const { return wrapped_string; }
operator std::string&() { return wrapped_string; }
};
Wrapping map will take a bit more work, as you'd have to duplicate the entire interface, including typedefs. Note: this code is not tested, treat it as proof-of-concept, to steer you in the right direction.
What about a small wrapper class for std::string?
class StringWrapper {
StringWrapper() { //... your code
}
operator std::string&() { return m_string; } // or something like that
private:
std::string m_string;
};
Now you use the following map-type:
std::map<T1, StringWrapper> mymap;
In the constructor of StringWrapper you can define custom actions. It gets called when you insert an item into your map.