I have an
stl::map that has the key defined as an object I defined, and int. The use of the map is as follows:
I have a list of the specific object and I want to count how many identical objects I have. So I insert the objects into the map.if the object already exists in the map I increase it's value (hence the counter). The object has all the basic operators defined. The object consist of 5 strings. The == operator defined as the comparison of all 5 strings, and logically is meaningfull in the context. The problem is that the operator < has no logic meaning in the context. I care only if the objects are equal. I can't define which of two different objects is bigger.so for the sake of stl map defined this operator as the result of if else ladder and in each if I compared with "<" another string of the five. If true return true else, if.... And the last else returns false. In a specific case of the object , where I had three identical instances, I got the map containing two identical objects as keys, one of them had the counter of 1 and the other had 2.
i can't understand what is the problem and how could it happen.
For those who requested some code examples - for reason i can't explain - i can't post the code itself, but i will write a good example of it(please ignore little things like missing ';' - i wrote it in 5 minutes):
class Example
{
private:
string one;
string two;
string three;
string four;
string five;
public:
inline Example (string a_one,string a_two, string a_four, string a_five) :
one(a_one),two(a_two),three(a_three),four(a_four),five(a_five)
{}
inline bool operator == (const Example& other) const
{
if (one == other.one)
{
if (two == other.two)
{
if (three == other.three)
{
if (four == other.four)
{
if (five == other.five)
{
return true;
}
}
}
}
}
return false;
}
inline bool operator < (const Example& other) const
{
if (one < other.one)
{
return true;
}
else if (two < other.two)
{
return true;
}
else if (three < other.three)
{
return true ;
}
else if (four < other.four)
{
return true;
}
else if (five < other.five)
{
return true;
}
else
{
return false;
}
}
}
void CountExample(Example& example,std::map<Example,int>& counters);
void main()
{
std::map<Example,int> counters;
std::list<Example> examples = GetExamples();
//GetExamples defined elsewhere, and initializes examples with a long list of instances of Example
std::list<Example>::const_iterator Iter;
for (Iter = examples.begin();Iter != examples.end();Iter++)
{
CountExample(*Iter);
}
PrintCounters(counters);//PrintCounters defined elsewhere and prints the map to a file
}
void CountExample(Example& example,std::map<Example,int>& counters)
{
std::map<Example,int>::const_iterator Iter;
Iter = counters.find(example);
if (Iter ==counters.end()) //means the specific Example is not in the map
{
counters.insert(std::pair<Example,int>(example,1));
}
else
{
counters[example] += 1;
{
}
If you have a reasonably modern compiler, that ladder of comparisons can be replaced with a single comparison between two std::tie()'d tuples:
#include <tuple>
...
bool operator== (const Example& other) const
{
return std::tie(one, two, three, four, five)
== std::tie(other.one, other.two, other.three, other.four, other.five);
}
bool operator < (const Example& other) const
{
return std::tie(one, two, three, four, five)
< std::tie(other.one, other.two, other.three, other.four, other.five);
}
Incidentally, it may be simpler to use a std::multiset to count the number of times a particular element is stored in an associative container, that simplifies CountExample to a one-liner
void CountExample(const Example& example, std::multiset<Example>& counters)
{
counters.insert(example);
}
Although printing becomes a bit more tricky:
void PrintCounters(const std::multiset<Example>& counters)
{
for(auto i=counters.begin(); i!=counters.end(); i = counters.upper_bound(*i))
std::cout << *i << ":" << counters.count(*i) << '\n';
}
Test on ideone: http://ideone.com/uA7ao
To make a comparison with multiple elements, each element that you compare will have three outcomes: less than, greater than, or equivalent. You must account for all of these cases.
bool LessThan(const MyClass & left, const MyClass right)
{
if (left.one < right.one)
return true;
else if (right.one < left.one)
return false;
// equivalent in one
if (left.two < right.two)
return true;
else if (right.two < left.two)
return false;
// equivalent in one and two
...
return false;
}
You need to provide an operator< for you type. This can be pretty tedious to write, but you can simply it by using a Boost.Tuple - that way, the tuple handles the comparisons, leaving your code easier to read, write and understand.
#include <boost/tuple/tuple.hpp>
#include <boost/tuple/tuple_comparison.hpp>
#include <string>
struct Object
{
std::string a;
std::string b;
std::string c;
};
bool operator<(const Object& obj1, const Object& obj2)
{
return (boost::tie(obj1.a, obj1.b, obj1.c) <
boost::tie(obj2.a, obj2.b, obj2.c));
}
Edit: After thinking about the problem some more, I've decided to removed my older answer since it did not seem pertinent to the current problem being experienced. Your operator< method does seem to be fulfilling the requirements for a strict weak ordering, so I think the problem lies somewhere else, and so I'm leaving the following alternate solution below ...
It seem you're having issues creating a total order for your map, so you might want to look at std::unordered_map as an alternative that will directly apply your operator== for detecting equality, rather than using your operator< for a strict weak ordering ... you'll have to provide a hash-function for your class, but otherwise the use of the hash-table based std::unordered_map container is pretty straight-forward.
Related
Inspired by another question regarding java-script language. Can the expression
(a==1)&&(a==2)&&(a==3)
evaluate to true in C++? (And if so, can it actually be useful?)
Yes it can:
class Foo
{
public:
bool operator==(int a)
{
return true;
}
};
Then, let a be of type Foo and voila.
Can this actually be useful? I don't really see it being useful no.
Can the expression evaluate to true in C++?
Yes, nothing is impossible...
struct A {
int x = 0;
};
bool operator==(A& a, int num) {
return ++a.x == num;
}
Then:
if ((a == 1) && (a == 2) && (a == 3)) {
std::cout << "meow" << std::endl;
}
prints meow.
But I have no idea of any practical usage of such weird overloading and, hopefully, will never see such code in production.
Could be somewhat useful.
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
struct Foo {
std::vector<int> v = {1,2,3};
};
bool operator==(const Foo& foo, int i) {
return std::any_of(foo.v.begin(), foo.v.end(), [=](int v){ return v == i; });
}
int main() {
Foo a;
if (a==1 && a==2 && a==3)
cout << "Really??" << endl;
return 0;
}
As it was noticed before, this trick could be performed with volatile. This is more honest approach compared to operator changing. Just let us use two threads:
volatile int a;
void changingValue(){
std::srand(unsigned(std::time(0)));
while (true) {
a = (rand() % 3 + 1);
}
}
void checkingValue(){
while (true) {
if (a == 1 && a == 2 && a == 3) {
std::cout << "Good choice!" << std::endl;
}
}
}
int main() {
std::thread changeValue = std::thread(changingValue);
changeValue.detach();
std::thread checkValue = std::thread(checkingValue);
checkValue.detach();
while (true){
continue;
}
}
Moreover, this code in my case is working well with no volatile declaration. As far as I understand, it should depend on compiler and processor. Maybe someone could correct it, if I'm wrong.
Other things not mentioned yet (source):
a might have overloaded operator int(), the operator for implicit conversion to int (instead of operator== as covered by other answers).
a might be a preprocessor macro.
Example of the latter:
int b = 0;
#define a ++b
if ((a==1)&&(a==2)&&(a==3))
std::cout << "aha\n";
Operator overloading and macros are trivial solutions to such a riddle.
And if so, can it actually be useful?
Well, with some imagination... One possible use case I can think of are unit tests or integration tests in which you want to make sure that your overloaded operator== for some class works correctly and you know for sure that it works incorrectly if it reports equality for different operands when it's not supposed to do that:
class A {
public:
A(int i);
bool operator==(int i) const;
// ...
};
A a(1);
if ((a==1)&&(a==2)&&(a==3)) {
// failed test
// ...
}
I assume a requirement is a valid program free of undefined behaviour. Otherwise simply introduce something like a data race and wait for the right circumstances to occur.
In a nutshell: Yes, it is possible for user-defined types. C++ has operator overloading, so the related answers from the JavaScript question apply. a must be a user-defined type because we compare against integers and you cannot implement operator overloads where all parameters are built-in types. Given that, a trivial solution could look like:
struct A {}
bool operator==(A, int) { return true; }
bool operator==(int, A) { return true; }
Can something like this be useful? As the question is stated: almost certainly not. There is a strong semantic meaning implied by the operator symbols used in their usual context. In the case of == that’s equality comparison. Changing that meaning makes for a surprising API, and that’s bad because it encourages incorrect usage.
However there are libraries that explicitly use operators for completely different purposes.
We have an example from the STL itself: iostream’s usage of << and >>.
Another one is Boost Spirit. They use operators for writing parsers in an EBNF like syntax.
Such redefinitions of the operator symbols are fine because they make it perfectly obvious that the usual operator symbols are used for a very different purpose.
Just to show my own ideas. I was thinking of some data structure like a stream buffer or a ring buffer.
We can with template inheritance "hide away the operator" and nothing will be altered in the data structure in itself but all checking will be done in the template superclass.
template<class C>
class Iterable{
C operator==(int a);
public:
Iterable(){pos = 0;}
int pos;
};
template<class C>
class Stream : public Iterable<Stream<C>>{
public:
Stream(C a){ m[0] = a; }
C m[32];
int operator==(int a){
return (m[this->pos++]==a); }
};
int main(){
Stream<int> a(1);
a.m[0] = 1; a.m[1] = 3; a.m[2] = 2;
if(a==1 && a==3 && a==2)
std::cout<<"Really!?"<<std::endl;
return 0;
}
In this case the == to an integer could be a short-cut for "is the next packet/element in the stream of this ID number" for example.
I have a structure that contains x amount of integers, It is required that every last one of them be non-zero. Here's my structure:
struct thingy_t{
int a, b, c /* and so on */;
bool init();
};
Over time I will be adding many other members to the structure, which makes it an issue if I forget to check if it's non-zero. That's why I wanted to automate it for every member.
In my init function, it attempts to get values for the members, and return false if any of them are 0.
So far I have this:
bool thingy_t::init(){
a = GetValue(/* blah blah */); // Will return 0 if it can't find anything
b = GetValue(/* other blah */);
/* and so on */
// Check if any value is zero
for(int* i = (int*)this
; i < (int*)((char*)this + sizeof(interfaces_t))
; i++){
if(!*i) return false;
}
return true;
}
I am looking for a better way of doing this that would be more readable and more memory safe, as I am playing with fire(pointers) in a way they probably aren't intended.
Also, sorry for the for loop, I tried to make it more readable by wrapping it, but I probably made it worse.
There isn't a natural way to iterate over the struct and check for certain values of the members you have, so the better option for you, in my opinion, should be either make a better design for your task or make sure that you check for incorrect values on each access to that struct.
I'd simple implement the type to contain an array of int or (possibly better) a standard container.
If the number of values is specified at compile time ....
struct thingy_t
{
int x[number];
bool all_non_zero() const;
};
bool thingy_t::all_non_zero() const
{
for (int i = 0; i < number; ++i)
if (!number[i]) return false;
return true;
}
If the number is not specified at compile time, I'd use a standard container
struct thingy_t
{
std::vector<int> x;
thingy_t(std::size_t size) : x(size) {};
bool all_non_zero() const;
};
bool thingy_t::all_non_zero() const
{
for (std::vector<int>::const_iterator it = x.begin(), end = x.end();
it != end number; ++it)
if (!(*it)) return false;
return true;
}
The above works for all versions of C++, but may be simplified in C++11 or later.
bool thingy_t::all_non_zero() const
{
for (const auto &element : x)
if (!element) return false;
return true;
}
Naturally, you will need other functions to actually store values in the array or vector.
The code won't change if the number of integers changes. You will need to somehow track separately the meaning of each element.
I solved my own question while enjoying a nice breakfast.
Here's how I solved it:
struct thingy_t{
union{
struct{
int a, b, c;
}
int arr[3];
}
}
That way I can access variables via. their name and also their index in an array so I can check if each value is non-zero easier (creds: James Root for the array inspiration)
I found that when writing animations I sometimes run into having to go through a for loop once, then iterate the value down afterwards. This was generally used for jump animations, or disappear then appear again animations.
Here's an example of what I had done -
// Make the sprite slowly disappear
for (int i = 256; i > 0; --i)
{
sprite.opacity(i);
draw();
}
// Make the sprite slowly appear again
for (int i = 0; i < 256; ++i)
{
sprite.opacity(i);
draw();
}
Every time I did this I had a deep feeling that it was too much. What would be a nicer way of going about this? I'm not entirely sure what would be best practice. I imagine I could use reverse_iterator, but I'm also not sure how I would implement it.
Consider the use of <cmath> abs() function:
for( int i = -255; i <= 255; i++)
use( abs( i ) );
You can use the absolute value function abs() defined in <cmath>. It will halve the code written in your case.
for(int i=0; i<512; ++i)
{
sprite.opacity( abs(256-i) );
draw();
}
I believe in the situation you are describing, you have to iterate through the sprites to set the opacity of each sprite. Whether you use a for loop, or a reverse_iterator, the time spent is going to be the same. Any implementation of the reverse_iterator will still have to iterate through each sprite. There might be ways to make it easier to read, but in the end the algorithm will come down to the same. For example, you could take advantage of the stack and call the sprites recursively to increase the opacity and then decrease on the way back out; however, I see no gain in doing so the algorithm time would still end up being the same.
In some cases, you just need to bite the bullet and spend the time doing things in a way that may seem like (or even be) brute force.
That's a great way to iterate through a loop both forward and "in reverse" - one commonly used by C++ programmers.
For your sprite, it appears that the 256 range (you might consider setting a const int RGB_RANGE equal to 256 - or a more appropriate identifier) is all that is needed; however, were the size of your object dynamic, you could also consider using the .size() function (something like an ArrayList or a vector - here is where something like an iterator would be useful):
for (i = 9; i < RGB_RANGE; i++)
{
// CODE
}
The above code being an example of the first const suggestion. Remember, simple code is never a bad thing - it means you are doing something right.
If you don't want to use abs, I'd go with something like :
template<typename Func>
void animate (size_t step_count, Func && f)
{
size_t step;
for (step = step_count ; step > 0 ; --step)
f(step - 1);
for (step = 1 ; step < step_count ; ++step)
f(step);
}
Use case :
animate(256, [](size_t step)
{
sprite.opacity(step);
draw();
});
If you wish to just iterate a range up and down again, you can go the very crazy route and just define a "container" (or range, in boost lingo) that provides iterators (well, technically they are more almost-iterators) which allow you to express exactly what you intend to do:
for(auto i : down_and_up(3)) ::std::cout << i << "\n";
For example should print
3
2
1
0
1
2
Sadly, there is not much support in the standard library for types like this, although boost provides boost::iterator_range, boost::counting_iterator, and boost::join that, in concert with std::reverse_iterator, can provide down_and_up. Writing one yourself if fairly simple (although verbose), as long as you do not completely abuse it:
struct down_and_up
{
size_t from;
down_and_up(size_t const from) : from(from) { }
struct iterator : public ::std::iterator<::std::forward_iterator_tag, size_t> {
size_t cur;
bool down;
iterator(size_t cur, bool down) : cur(cur), down(down) { }
size_t operator*() const { return cur; }
iterator& operator++()
{
if(down)
{
--cur;
if(0 == cur) down = false;
}
else ++cur;
return *this;
}
friend bool operator==(iterator const& lhs, iterator const& rhs) { return lhs.down == rhs.down && lhs.cur == rhs.cur; }
friend bool operator!=(iterator const& lhs, iterator const& rhs) { return lhs.down != rhs.down || lhs.cur != rhs.cur; }
};
iterator begin() const { return iterator{ from, true }; }
iterator end() const { return iterator{ from, false }; }
};
Note: If you wish, you can easily extend it with more container capabilities, like a value_type member typedef, but this definition is enough for the above example.
P.S.: The boost way, for your entertainment:
boost::iterator_range<boost::counting_iterator<size_t>> up(boost::counting_iterator<size_t>(0), boost::counting_iterator<size_t>(3));
boost::iterator_range<std::reverse_iterator<boost::counting_iterator<size_t>>> down(
std::reverse_iterator<boost::counting_iterator<size_t>>(boost::counting_iterator<size_t>(4)),
std::reverse_iterator<boost::counting_iterator<size_t>>(boost::counting_iterator<size_t>(1)));
for(auto i : boost::join(down, up)) ::std::cout << i << "\n";
Basically, I want to save a set of pointers, which should be sorted by my customized compare function, but the uniqueness should still be determined by the pointer itself.
However:
#include <iostream>
#include <string>
#include <set>
#include <utility>
#include <functional>
using namespace std;
// count, word
typedef pair<int, string> WordFreq;
struct WordFreqPointerCmp
{
bool operator()(const WordFreq* lhs, const WordFreq* rhs) const
{
return lhs->first > rhs->first;
}
};
int main()
{
set<WordFreq*, WordFreqPointerCmp> s;
s.insert(new WordFreq(1, "word1")); // Inserted
s.insert(new WordFreq(1, "word2")); // This is not inserted
s.insert(new WordFreq(3, "word3")); // Inserted
cout << s.size() << endl;
for (set<WordFreq*, WordFreqPointerCmp>::iterator it = s.begin();
it != s.end(); ++it)
{
cout << (*it)->second << ": " << (*it)->first << endl;
}
return 0;
}
/* Output:
2
word3: 3
word1: 1
*/
As you can see that the ordering is correct, but the duplicate testing is wrong. What I am trying to do is:
For ordering, I want to use WordFreqPointerCmp;
For duplicate testing, I want to use the original meaning of raw Pointer comparsion, i.e., the address comparison, which means, even the following set should have two entries in the set;
set<WordFreq*, WordFreqPointerCmp> s;
s.insert(new WordFreq(1, "word1"));
s.insert(new WordFreq(1, "word1"));
I also tried the following, but same result:
template<>
struct greater<WordFreq*>
{
bool operator()(WordFreq* const& lhs, WordFreq* const& rhs) const
{
return lhs->first > rhs->first;
}
};
set<WordFreq*, greater<WordFreq*> > s;
while this post is ancient, I've just faced the same issue, so it may help somebody..
In your code you only handle one value, but what if values are the same? Then set treats it as the same element. The proper solution would be to extend your compare function to give set additional information how to test for duplicates. It can be something arbitrary like comparing strings, for example in your case:
struct WordFreqPointerCmp
{
bool operator()(const WordFreq* lhs, const WordFreq* rhs) const
{
if (lhs->first == rhs->first)
return lhs->second > rhs->second;
else
return lhs->first > rhs->first;
}
};
I am not sure what the problem is. Since you want the first component of your pair to be the key that determines uniqueness, inserting two "WordFreq" with key = 1 should lead to the second evict the first. Results match expectation here.
Update: I guess, I misunderstood something. Since you want duplicate keys, you are probably looking for multimap.
Update 2: To make this work you need to add a step before adding a new object: Iterate over all values of the same key, and kick those out that point to the object being added. Also, I forgot to mention there is multiset which is probably what you'd prefer.
I admit, here is where Java's HashSet with it's separate order and equality tests come in handy. Maybe you can find a C++ version of it.
I am writing some code where I am storing lots of objects that I want to get back based on set criteria. So to me it made sense to use a map with an object as a key. Where the object would contain the "set criteria".
Here is a simplified example of the kind of objects i am dealing with:
class key
{
int x,y,w,h;
}
class object
{
...
}
std::map<key, object, KeyCompare> m_mapOfObjects;
Quite simple, the first thought was to create a compare functions like this:
struct KeyCompare
{
bool operator()(const key &a, const key &b)
{
return a.x < b.x || a.y < b.y || a.w < b.w || a.h < b.h;
}
}
but then i thought the chances of this returning true are quite high. So I figured this would lead to a very unbalanced tree and therefore slow searching.
My main worry is that as I understand it, std::map uses that one function in this way:
if( keyCompare(a,b) )
{
//left side
}
else if (keyCompare(b,a))
{
//right side
}
else
{
//equal
}
So i can't just use a.x < b.x, because then anything with the same x would be considered equal, which is not what i want. I would not mind it ordering it in this way but its the "equal" bit i just can't seem to solve without making it unbalanced.
I figure multiplying them all together is a no no for obvious reasons.
So the only solution i could come up with was to create a "UID" base on the info:
typedef long unsigned int UIDType;
class key
{
private:
UIDType combine(const UIDType a, const UIDType b)
{
UIDType times = 1;
while (times <= b)
times *= 10;
return (a*times) + b;
}
void AddToUID(UIDType number)
{
if(number < m_UID)
{
m_UID = combine(number, m_UID);
}
else
{
m_UID = combine(m_UID, number);
}
}
UIDType UID;
public:
int x,y,w,h;
key()
{
AddToUID(x);
AddToUID(y);
AddToUID(w);
AddToUID(h);
}
}
struct KeyCompare
{
bool operator()(const key &a, const key &b)
{
return a.UID < b.UID;
}
}
But not only does that feel a little hacky, "long unsigned int" isn't big enough to hold the potential numbers. I could put it in a string, but speed is an issue here and I assumed an std::string < is expensive. Overall though the smaller i can make this object the better.
I was wondering if anyone has any suggestions for how to do this better. Perhaps i need to use something other then a std::map or perhaps there is another overload. Or perhaps there is something glaringly obvious that i'm missing here. I really feel like i'm over-complicating this, perhaps im really barking up the wrong tree with a map.
As i was writing this it occurs to me that divide is another way to get a "unique" number but that could also equal very large numbers
All you need is to implement a strict weak ordering, which you can easily achieve using std::tie, which has a less than comparison operator< which performs a lexicographical comparison:
#include <tuple>
struct KeyCompare
{
bool operator()(const key& a, const key& b) const
{
return std::tie(a.x, a.y, a.w, a.h) < std::tie(b.x, b.y, b.w, b.h);
}
}
If you do not have the required C++11 support, you can use std::tr1::tie from <tr1/tuple> or equivalent versions from the boost libraries.
I feel juanchopanza has a very good solution, for those who do not have C++11 support or boost libraries
I found a very simple solution on:
What's the simplest way of defining lexicographic comparison for elements of a class?
This solution works for my particular problem a little better then tuple would (as i also have an array of values that i would like to consider). But I would highly recommend considering tuple in future, as will I.
struct keyCompare
{
bool operator()(const key &a, const key&b)
{
if(a.x != b.x) return a.x < b.x;
if(a.y != b.y) return a.y < b.y;
if(a.w != b.w) return a.w < b.w;
if(a.h != b.h) return a.h < b.h;
return false; //they must be equal
}
}
thanks to juanchopanza for his answer and to anyone else who had a look in