how to compare a vector of pointers and string ? - c++

struct compare{
string k;
compare(string a) : k(a){}
bool operator()(const product* t)const{
return (t->productdetails.getName()<k);
}
};
void cashier::calculate(string s,vector<product*> &a){
//this is lambda (tried to use it ,but doesn't work)
auto comp=[](const product* t, const string b)
{
return (b < t->productdetail.getName());
};
if (std::binary_search ( a.begin(), a.end(),s, compare(s)))
cout << "found!\n";
else
std::cout << "not found.\n";
}
I'm stuck in this part for a long time.
the vector holds product(class) pointer. product pointer points to productdetail which has two variables (name and price)
I need to look up (string s) in the vector and if the string s is in vector (product->productdetail.getName()), I need to return the price..
how to compare proudct* and string s ?
my teacher gave me advice that i need to make anther string conversion function since the comparing type need to be the same..
(I tried to use lambda and it didn't work and changed to compare function)

I concur with #Fureeish, using bare pointers in modern C++ is not a good choice, unless you absolutely have to.
That said, writing predicates for the standard library requires a good knowledge of the library methods you are using. Have a look at std::binary_search documentation. A simple application is to search for the same type as you are searching through. In other words your needle is the same type as what is in your haystack. Here is an example:
#include <iostream>
#include <vector>
#include <algorithm>
class product {
public:
class product_details {
public:
std::string name;
double price;
};
product_details productDetails{};
product(std::string const &name, double price) : productDetails{ name, price} {}
};
struct product_compare {
bool operator()(product const &lhs, product const &rhs) {
return lhs.productDetails.name < rhs.productDetails.name;
}
};
int main(int argc, char *argv[])
{
std::vector<product> producList{
{ "toaster", 74.99 },
{ "blender", 103.99 },
{ "slow cooker", 142.99 }
};
product_compare productCompare{};
std::sort(producList.begin(), producList.end(), productCompare);
product searchProduct{"slow cooker", 142.99};
if (std::binary_search(producList.begin(), producList.end(), searchProduct, productCompare))
std::cout << "Found!\n";
else
std::cout << "Not found!\n";
}
But that lacks elegance. Your needle can be a different type, the answer is actually in this SO question. Here is a rewrite that takes advantage of this. This idiom is a bit more complicated to write but is better related to the actual problem and therefore easier to understand. Ultimately you never know which side of the compare is going to be needle and which side is going to be hay. So you have to write your compare predicate to accept both comparisons.
#include <iostream>
#include <vector>
#include <algorithm>
class product {
public:
class product_details {
public:
std::string name;
double price;
};
product_details productDetails{};
product(std::string const &name, double price) : productDetails{ name, price} {}
};
struct product_compare {
bool operator()(std::string const &lhs, product const &rhs) {
return lhs < rhs.productDetails.name;
}
bool operator()(product const &lhs, std::string const &rhs ) {
return lhs.productDetails.name < rhs;
}
};
// Used by std::sort
bool operator<(product const &lhs, product const &rhs) {
return lhs.productDetails.name < rhs.productDetails.name;
}
int main(int argc, char *argv[])
{
std::vector<product> producList{
{ "toaster", 74.99 },
{ "blender", 103.99 },
{ "slow cooker", 142.99 }
};
product_compare productCompare{};
std::sort(producList.begin(), producList.end());
if (std::binary_search(producList.begin(), producList.end(), std::string("slow cooker"), productCompare))
std::cout << "Found!\n";
else
std::cout << "Not found!\n";
}

Related

How to make a priority queue use a variable from custom a class (Ascending/descending)

I am having trouble with using the priority_queue in C++, I have a vector of priority queues, the priority queues contains several Person objects. Now I would like for the priority_queue to prioritize the Person objects based on their age. So I have something like this:
class Person
{
public:
string name;
int height;
int age;
};
std::vector<std::priority_queue<Person*>> Persons;
How do I make sure that whenever a person is added to one of the priority queues, that they are prioritized based on their age? And how would I do it in ascending/descending order?
You actually don't need the additional vector which wraps your priority_queue as the priority_queue itself has 2 additional default arguments:
(first one is the type, in your case Person*), second one is the container type and the third one is the compare predicate.
below you can see using a lambda function as a compare predicate for your priority queue.
#include <vector>
#include <string>
#include <queue>
#include <iostream>
using namespace std;
class Person
{
public:
string name;
int height;
int age;
Person(string n, int h, int a): name(n), height(h), age(a) {}
};
ostream& operator<<(ostream &cout, const Person* p) {
return cout << p->name << " height=" << p->height << " age=" << p->age << " ";
}
int main()
{
auto cmp = [](const Person* pl, const Person* pr) {
return (pl->age < pr->age);
};
priority_queue<Person*, vector<Person*>, decltype(cmp)> persons(cmp);
persons.push(new Person("a", 100, 10));
persons.push(new Person("b", 120, 20));
persons.push(new Person("c", 110, 15));
while (!persons.empty()) {
cout << persons.top() << endl;
persons.pop();
}
return 0;
}
You can pass a predicate as third parameter to detect sort order, declare two predicates for your Person*
struct AscendingPersonPredicate
{
bool operator() ( Person* p1, Person* p2) const
{
return p1->age < p2->age;
}
};
struct DescendingPersonPredicate
{
bool operator() ( Person* p1, Person* p2) const
{
return p1->age > p2->age;
}
};
Then declare your vector as:
std::priority_queue<Person*, vector<Person*>, AscendingPersonPredicate> Persons;
or
std::priority_queue<Person*, vector<Person*>, DescendingPersonPredicate> Persons;
std::priority_queue has an interface for what you require. It takes three template parameters:
template<
class T,
class Container = std::vector<T>,
class Compare = std::less<typename Container::value_type>
> class priority_queue;
The third one is what you need to change to handle the comparison of elements.
// make a functor to do the comparisons
struct comparator
{
bool operator()(Person* lhs, Person* rhs) const {
// sort by age
return lhs->age < rhs->age; // switch the sign for reverse order
}
};
// have a type alias for convenience (typedef is fine too)
using pqueue = std::priority_queue<Person*, std::vector<Person*>, comparator>;
int main()
{
std::vector<pqueue> persons;
}
You can implement like this :
#include <iostream>
#include <queue>
#include <vector>
#include <string>
using namespace std;
class Person
{
public:
string name;
int height;
int age;
};
struct OrderByAge
{
bool operator() (Person const &a, Person const &b) { return a.age > b.age; }
};
int main()
{
vector<priority_queue<Person, std::vector<Person>,OrderByAge> > personPQVec{ 1 };
Person p1{ "nitendra",5,39 };
Person p2{ "bhosle",6,34 };
Person p3{ "nit",4,33 };
personPQVec[0].push(p1);
personPQVec[0].push(p2);
personPQVec[0].push(p3);
while (!personPQVec[0].empty()) {
cout << "Name: " << (personPQVec[0]).top().name << ", age: " << (personPQVec[0]).top().age << endl;
(personPQVec[0]).pop();
}
system("pause");
return 0;
}

Is it possible to overload operator "..." in C++?

#include <iostream>
#include <vector>
using namespace std;
//
// Below is what I want but not legal in current C++!
//
vector<int> operator ...(int first, int last)
{
vector<int> coll;
for (int i = first; i <= last; ++i)
{
coll.push_back(i);
}
return coll;
}
int main()
{
for (auto i : 1...4)
{
cout << i << endl;
}
}
I want to generate an integer sequence by using syntax 1...100, 7...13, 2...200 and the like.
I want to overload ... in C++.
Is it possible?
Is it possible?
No, it isn't possible.
... isn't an operator but a placeholder for variadic arguments.
There is no ... operator in C++, so you can't overload it.
However, you can use an ordinary name such as range.
Assuming a header that defines a suitable range function, your intended program
int main()
{
for (auto i : 1...4)
{
cout << i << endl;
}
}
… can then look like this:
#include <p/expressive/library_extension.hpp>
using progrock::expressive::range;
#include <iostream>
#include <vector>
using namespace std;
int main()
{
for( auto i : range( 1, 4 ) )
{
cout << i << endl;
}
}
This is actual working code using the Expressive C++ library's range
implementation. However, that
library is currently in its very infant stages, in flux, with all kinds of
imperfections and fundamental changes daily. Also it implements an extended
dialect of C++, that is as yet unfamiliar to all but myself, so that posting the range implementation here where pure C++ is expected, would possibly/probably provoke negative reactions; I'm sorry. But you can easily translate that implementation to raw C++. It's Boost 1.0 license.
As mentioned in the other answers this is not possible since ... is not a valid operator, but in this language you can always create weird idioms like this:
#include <iostream>
struct int_it
{
int_it (int l, int r): left(l), right(r){}
void operator++() { left++;}
bool operator!=(const int_it& rhs) { return left != rhs.right;}
int operator*(){ return left;};
int left;
int right;
};
class range_op
{
public:
static range_op op() { return {0,0}; }
operator int() { return right - left; }
auto begin(){ return int_it{left, right}; }
auto end(){ return int_it{right,right}; }
private:
range_op(int l, int r): left(l), right(r){}
int left;
int right;
friend range_op operator*(int lhs, range_op r);
friend range_op operator*(range_op r, int rhs);
};
range_op operator*(int lhs, range_op r)
{
return range_op{lhs, r.right};
}
range_op operator*(range_op d, int rhs)
{
return range_op{d.left, rhs};
}
const auto o = range_op::op();
int main() {
for (int i : 2*o*6)
{
std::cout << i << std::endl;
}
return 0;
}
This is just a quick example, so no range checks and a lot of bugs.

Is it possible to introspect on methods using Boost Hana?

Boost Hana provides the ability to introspect on class member fields in a simple and beautiful way:
// define:
struct Person {
std::string name;
int age;
};
// below could be done inline, but I prefer not polluting the
// declaration of the struct
BOOST_HANA_ADAPT_STRUCT(not_my_namespace::Person, name, age);
// then:
Person john{"John", 30};
hana::for_each(john, [](auto pair) {
std::cout << hana::to<char const*>(hana::first(pair)) << ": "
<< hana::second(pair) << std::endl;
});
However, the documentation only mentions member fields. I would like to introspect on methods also. I've tried to naively extend the example with a method:
struct Foo {
std::string get_name() const { return "louis"; }
};
BOOST_HANA_ADAPT_STRUCT(::Foo, get_name);
This compiles. However, as soon as I try to use it, using code similar to the above (for_each...), I get many compile errors. Since there are no examples that show introspection of methods, I'm wondering whether it is supported.
My original answer was crap; sorry for that. Here's a rewrite that actually answers the question.
I just added a macro to allow easily defining a Struct with custom accessors. Here's how you could do it:
#include <boost/hana/adapt_adt.hpp>
#include <boost/hana/at_key.hpp>
#include <boost/hana/string.hpp>
#include <cassert>
#include <string>
namespace hana = boost::hana;
struct Person {
Person(std::string const& name, int age) : name_(name), age_(age) { }
std::string const& get_name() const { return name_; }
int get_age() const { return age_; }
private:
std::string name_;
int age_;
};
BOOST_HANA_ADAPT_ADT(Person,
(name, [](auto const& p) { return p.get_name(); }),
(age, [](auto const& p) { return p.get_age(); })
);
int main() {
Person bob{"Bob", 30};
assert(hana::at_key(bob, BOOST_HANA_STRING("name")) == "Bob");
assert(hana::at_key(bob, BOOST_HANA_STRING("age")) == 30);
}
That code should work on master. Otherwise, if you need more control over the definition of your accessors or the keys used to map to them, you can also define the whole thing by hand:
namespace boost { namespace hana {
template <>
struct accessors_impl<Person> {
static auto apply() {
return hana::make_tuple(
hana::make_pair(BOOST_HANA_STRING("name"), [](auto&& p) -> std::string const& {
return p.get_name();
}),
hana::make_pair(BOOST_HANA_STRING("age"), [](auto&& p) {
return p.get_age();
})
);
}
};
}}
You can find more information about how to define Structs in the reference for the Struct concept.

C++ streams operator << and manipulators / formatters

First, most of my recent work was Java. So even though I "know" C++, I do not want to write Java in C++.
And C++ templates are one thing I will really miss when going back to Java.
Now that this out of the way, if I want to do create a new stream formatter, say pic, that will have a single std::string parameter in it's constructor.
I would like the user to be able to write something like:
cout << pic("Date is 20../../..") << "100317" << endl;
The output should be
Date is 2010/03/17
How do I write the pic class? when the compiler sees the cout what are the underlying steps the compiler does?
Edit
Would it be more C++ to change that code into:
cout << pic("Date is 20../../..", "100317") << endl;
And possibly be easier to write the pic function as a standalone function (possibly template)?
It sounds like you are trying to write an alternate form of printf(). I'm not sure that this is a good idea, but if you decide to do it, you should definitely write it as a free function, because the manipulator issues (which have nothing to do with formatting using a format string) go away. I would also avoid templates to start with, and simply design and write the string version:
void pic( ostream & os, const string & fmt, const string & val );
Before writing such a function, you will have to be very clear in your mind what its semantics are, which I don't believe you are yet.
you might have a look at boost::format library.
somethings like this should work (if you can afford spliting your string first)
#include <iostream>
#include <string>
#include <boost/format.hpp>
int main()
{
const char* a = "102030";
std::string year(a, a + 2);
std::string month(a + 2, a +4);
std::string day(a + 4);
std::cout << boost::format("Date is 20%1%/%2%/%3%")% year % month % day << std::endl;
}
There are 2 questions here.
One deals with stream manipulators, follow the quote.
The other one deals with formatting issues.
Formatting is hard, especially the way you indicate it, because it involves being able to parse the format and generate an AST representation that will then be called to actually format the string. Parsing means that you need to define a small grammar etc...
There are libraries like Boost.Spirit who deals with parsing / generating, and they are much more complicated than the 'simple' Boost.Format (which itself is not that simple).
Now, could you forgo parsing ?
class Date
{
public:
Date(year_t year, month_t month, day_t day);
year_t getYear() const;
month_t getMonth() const;
day_t getDay() const;
private:
year_t mYear;
month_t mMonth;
day_t mDay;
};
The advantage of this class are multiple:
Structured information: parses one, reads as much as you wish
Validation: root out invalid date (29 Feb 2010 ?)
No ambiguity: is "100102" actually the "1st Feb 2010" or "2nd Jan 2010" ? (at least not once it's parsed)
Then, you can do the same for the format, by creating a little formatting engine.
template <class T>
class Formatter
{
public:
virtual ~Formatter() {}
virtual Formatter* clone() const = 0;
virtual std::string evaluate(const T& item) const = 0;
};
template <class T>
class FormatterConstant: public Formatter
{
public:
explicit FormatterConstant(const std::string& s): mValue(s) {}
virtual Formatter<T>* clone() const { return new FormatterConstant(*this); }
virtual std::string evaluate(const T&) const { return mValue; }
private:
std::string mValue;
};
template <class T>
class FormatterComposite: public Formatter<T>
{
typedef std::vector< const Formatter<T>* > formatters_type;
typedef typename formatters_type::const_iterator const_iterator;
public:
// Need suitable Copy and Assignment Constructors
~FormatterComposite()
{
for(const_iterator it = mFormatters.begin(), end = mFormatters.end();
it != end; ++it) delete *it;
}
virtual Formatter<T>* clone() const { return new FormatterComposite(*this); }
virtual std::string evaluate(const T& item) const
{
std::string result;
for(const_iterator it = mFormatters.begin(), end = mFormatters.end();
it != end; ++it) result += (*it)->evaluate();
return result;
}
void imbue(std::ostream& s) { mStream = &s; }
FormatterComposite& operator<<(const std::string& s)
{
mFormatters.push_back(new FormatterConstant<T>(s); }
return *this;
}
FormatterComposite& operator<<(const Formatter<T>& formatter)
{
mFormatters.push_back(formatter.clone());
return *this;
}
std::ostream& operator<<(const T& item) const
{
return (*mStream) << this->evaluate(item);
}
private:
std::ostream* mStream;
formatters_type mFormatters;
};
template <class T>
FormatterComposite& operator<<(std::ostream& s, FormatterComposite& c)
{
c.imbue(s);
return c;
}
// Usage
class DateOfYear: public Formatter<Date>
{
public:
Formatter<Date>* clone() const { return new DateOfYear(*this); }
std::string evaluate(const Date& d) const { return toString(d.getYear()); }
};
extern const DateOfYear year;
int main(int argc, char* argv[])
{
FormatterComposite<Date> formatter;
Date date;
std::cout << formatter << "Date is 20"
<< year << "/" << month << "/" << day << date;
return 0;
}
Here, you forgo parsing. Of course it means the format is hardcoded...
Here is the initial solution to what I did. Only issue is that I'm still not able to templatize it. If I do, then calling the pic formatter would look like pic<float>("$(...)", 2.56) and the code would be messy.
#include <iostream>
#include <string>
using namespace std;
class pic {
private:
const string& _v;
const string& _pic;
public:
pic(const string& p, const string& v) : _v(v), _pic(p) {
}
friend ostream & operator<<(ostream& os, const pic& p) {
bool done = false;
int pi = 0;
int vi = 0;
while (!done) {
os << (p._pic[pi] == '.' ? p._v[vi++] : p._pic[pi]);
done = ++pi > p._pic.length() || vi > p._v.length();
}
return os;
}
};
int main(int argc, char** argv) {
cout << "The formatted date is: " << pic("20../../..", "100317") << endl;
return 0;
}

Need help with STL sort algorithm

I'm having some troubles with using the std::sort algorithm here. I was reading that you can just overload the less than operator to sort classes, but I have been getting all sorts of errors. I have also tried using a functor as you can see in the example I made below.
I was hoping somebody could see what I'm doing wrong here.
#include <iostream>
#include <vector>
#include <algorithm>
#include <stdlib.h>
#include <time.h>
class Thing {
public:
Thing(int val) {
this->_val = val;
}
bool operator<(Thing& rhs) {
std::cout << "this works!";
return this->val() < rhs.val();
}
int val() {
return this->_val;
}
protected:
int _val;
};
struct Sort {
bool operator()(Thing& start, Thing& end) {
return start.val() < end.val();
}
};
int main (int argc, char * const argv[]) {
std::srand(std::time(NULL));
std::vector<Thing> things;
for(int i = 0; i < 100; i++) {
Thing myThing(std::rand());
things.push_back(myThing);
}
if(things[1] < things[2]) {
//This works
}
//std::sort(things.begin(), things.end()); //This doesn't
//std::sort(things.begin(), things.end(), Sort()); //Neither does this
for(int i = 0; i < 100; i++) {
std::cout << things.at(i).val() << std::endl;
}
return 0;
}
Make your val() and operator<() const functions.
The same for Sort::operator() — take const Thing& instead of Thing&.
I believe you need to change
bool operator()(Thing& start, Thing& end) {
into
bool operator()(const Thing& start, const Thing& end) {
and
int val() {
into
int val() const {
IOW, your code needs to be const-correct and not claim it may modify things it in fact doesn't (nor needs to).
Try making operator< take its argument by const reference. You'll need to change its implementation to directly access _val or (preferably) make val() const as well when you do this (because a const member function can't call a non-const one).