and thanks for any input. I have a large dataset I am trying to manipulate. I am holding active elements in a list, and removing them when they become inactive. I want to hold all elements active and inactive in some data structure. Currently trying a map or an unordered_map, but am welcome to any suggestions.
I am compiling with
clang++ -std=c++11 -Wall -Wextra
When trying map:
#include <map>
std::map <class1, std::string> fullMap;
//and later...
for (std::list<class1>::iterator x = l.begin(); x != l.end(); x++)
{
fullMap[(*x)] = s
}
output reads:
error: invalid operands to binary expression ('const class1' and
'const class1') { return __x < __y; }
Even though I have overloaded the less than operator for class1.
This error originates at the overloaded bracket operators for map.
To circumvent I tried storing in an unordered_map.
#include <unordered_map>
std::unordered_map <class1, std::string> fullMap;
and the program fails at the initialization of fullMap with the even more confusing:
/usr/lib/gcc/x86_64-pc-linux-gnu/4.8.4/include/g++-v4/bits/hashtable_policy.h:830:23:
error: implicit instantiation of undefined template
'std::hash'
bool __use_ebo = !__is_final(_Tp) && __is_empty(_Tp)>
^
/usr/lib/gcc/x86_64-pc-linux-gnu/4.8.4/include/g++-v4/bits/hashtable_policy.h:1073:15: note: in instantiation of default argument for
'_Hashtable_ebo_helper<1, std::hash >' required here
private _Hashtable_ebo_helper<1, _H1>,
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/lib/gcc/x86_64-pc-linux-gnu/4.8.4/include/g++-v4/bits/hashtable_policy.h:1403:12: note: in instantiation of template class
'std::__detail::_Hash_code_base >, std::__detail::_Select1st, std::hash, std::__detail::_Mod_range_hashing,
std::__detail::_Default_ranged_hash, true>' requested here : public
_Hash_code_base<_Key, _Value, _ExtractKey, _H1, _H2, _Hash,
^
/usr/lib/gcc/x86_64-pc-linux-gnu/4.8.4/include/g++-v4/bits/hashtable.h:175:14:
note: in instantiation of template class
'std::__detail::_Hashtable_base >, std::__detail::_Select1st, std::equal_to, std::hash,
std::__detail::_Mod_range_hashing,
std::__detail::_Default_ranged_hash,
std::__detail::_Hashtable_traits >' requested here
: public __detail::_Hashtable_base<_Key, _Value, _ExtractKey, _Equal,
^
/usr/lib/gcc/x86_64-pc-linux-gnu/4.8.4/include/g++-v4/bits/unordered_map.h:100:18:
note: in instantiation of template class 'std::_Hashtable >,
std::allocator > >, std::__detail::_Select1st, std::equal_to, std::hash, std::__detail::_Mod_range_hashing,
std::__detail::_Default_ranged_hash, std::__detail::_Prime_rehash_policy,
std::__detail::_Hashtable_traits >' requested here
_Hashtable _M_h;
^
main.cpp:34:44: note: in instantiation of template class
'std::unordered_map,
std::hash, std::equal_to,
std::allocator > > >' requested here std::unordered_map fullMap;
^
/usr/lib/gcc/x86_64-pc-linux-gnu/4.8.4/include/g++-v4/bits/functional_hash.h:58:12:
note: template is declared here
struct hash;
I tried to cut the code down only to the relevant chunks, but let me know if more information is needed. Thanks for reading, any help is appreciated.
//
// class1.hpp
// class
//
// Created by Roach on 9/3/16.
// Copyright © 2016 Roach. All rights reserved.
//
#ifndef class1_hpp
#define class1_hpp
#include <iostream>
#include <sstream>
#include <iomanip>
#include <ctime>
class class1
{
public:
class1 ();
class1 (const class1& t); // copy constructor
~class1 (); // destructor
class1& operator = (const class1& t); // assignment operator
bool operator == (const class1& t); // comparison operator
void setSetting2 (std::string t);
void setSetting1 (std::string p);
void setSetting3 (double d);
void setSetting4 (double d);
std::tm getTime () const;
std::string getSetting2 () const;
double getSetting3 () const;
double getSetting4 () const;
std::string getSetting1 () const;
void setSetting3End (double d);
void setSetting4End (double d);
double getSetting3End () const;
double getSetting4End () const;
double getSetting3flag () const;
double getSetting4flag () const;
double getSetting3final () const; // in pips
double getSetting4final () const; // in pips
void processList (class1::class1 t);
void setNew ();
//void dump (std::ostream& os) const;
private:
std::string setting1;
double setting4;
double setting3;
std::tm setting2;
double setting4End_;
double setting3End_;
bool setting4Flag_;
bool setting3Flag_;
double setting4final_; // in pips
double setting3final_; // in pips
};
// stream extraction operator
std::ostream& operator << (std::ostream& os, const class1& s);
std::istream& operator >> (std::istream& is, class1& t);
endif /* class1_hpp */
The following is my overloaded less than operator (I know it isn't the most succinct or efficient):
bool class1::operator< (const class1& t)
{
if (this->time_.tm_year < t.time_.tm_year) {return true;}
else if (this->time_.tm_year > t.time_.tm_year) {return false;}
else if (this->time_.tm_mon < t.time_.tm_mon) {return true;}
else if (this->time_.tm_mon > t.time_.tm_mon) {return false;}
else if (this->time_.tm_mday < t.time_.tm_mday) {return true;}
else if (this->time_.tm_mday > t.time_.tm_mday) {return false;}
else if (this->time_.tm_hour < t.time_.tm_hour) {return true;}
else if (this->time_.tm_hour > t.time_.tm_hour) {return false;}
else if (this->time_.tm_min < t.time_.tm_min) {return true;}
else if (this->time_.tm_min > t.time_.tm_min) {return false;}
else if (this->time_.tm_sec < t.time_.tm_sec) {return true;}
else {return false;}
}
The issue is that std::map<key_type, value_type> requires a properly defined operator< for key_type, in this case your operator< is not const specified so it is incompatible with std::map as this data structure requires that the comparator not alter the key object in any way. Thus the solution is to mark class1::operator< as const.
The second error notes that no hash function-object has been applied for use with std::unordered_map, this would require the following framework:
auto class1_hasher = [](const class1& c) -> std::size_t { return {some hash based on c}; }
std::unordered_map<class1, std::string, decltype(class1_hasher)> um;
I think the issue here is that you're breaking the preconditions required of the std::map and std::unordered_map interfaces.
In a std::map, the key type needs to be able to be compared using the less-than operator. This means that you either need to provide an overload of operator <, or provide a custom comparator when you're using the std::map type. Since you didn't provide a way of doing this with your type, the internal implementation of std::map wasn't able to make an expression of the form
somethingOfTypeClass1 < somethingElseOfTypeClass1
compile, hence your error message.
When you switched to std::unordered_map, you ran into trouble because, in order to store something as a key in an std::unordered_map, you need to specialize the std::hash template on your custom type because the internal works of an unordered_map require that the type is hashable. That's the second error you got.
To fix this issue, either
Define a custom operator < or comparator type for class1, then use std::map, or
Define a custom std::hash for class1, then use std::unordered_map.
Its difficult to suggest best data structure until we know the functionality requirement. But the Below code is working for me on GCC 4.9.3.
Please check your include files and syntax.
#include <iostream>
#include <string>
#include <map>
#include <unordered_map>
#include <list>
using namespace std;
int main()
{
//LIST
std::list<int> myList;
myList.push_front(1);
myList.push_front(2);
myList.push_front(3);
myList.push_front(4);
//STRING
string s = "Test";
//MAP
std::map <int, std::string> fullMap;
for (std::list<int>::iterator x = myList.begin(); x != myList.end(); x++)
{
fullMap.insert(std::make_pair(*x,s));
}
//UNORDERED MAP
std::unordered_map <int, std::string> fullUnorderedMap;
for (std::list<int>::iterator y = myList.begin(); y != myList.end(); y++)
{
fullUnorderedMap.insert(std::make_pair(*y,s));
}
//PRINTING
for(auto it = fullMap.begin(); it != fullMap.end(); ++it)
{
cout<<it->first<<" "<<it->second<<endl;
}
for(auto it = fullUnorderedMap.begin(); it != fullUnorderedMap.end(); ++it)
{
cout<<it->first<<" "<<it->second<<endl;
}
}
Related
Inspired by Antony's Williams "C++ Concurrency in Action" I wanted to take a closed look at his thread safe hash map. I copied its code and added some output operators and this is what I came up with:
#include <boost/thread/shared_mutex.hpp>
#include <functional>
#include <list>
#include <mutex>
#include <iostream>
template <typename Key, typename Value, typename Hash = std::hash<Key>>
class thread_safe_hashmap
{
private:
class bucket_type
{
public:
typedef std::pair<Key, Value> bucket_value;
typedef std::list<bucket_value> bucket_data;
typedef typename bucket_data::iterator bucket_iterator;
bucket_data data;
mutable boost::shared_mutex mutex;
bucket_iterator find_entry_for(const Key& key) const
{
return std::find_if(data.begin(), data.end(),
[&](const bucket_value& item) { return item.first == key; });
}
public:
void add_or_update_mapping(Key const& key, Value const& value)
{
std::unique_lock<boost::shared_mutex> lock(mutex);
bucket_iterator found_entry = find_entry_for(key);
if (found_entry == data.end())
{
data.push_back(bucket_value(key, value));
}
else
{
found_entry->second = value;
}
}
};
std::vector<std::unique_ptr<bucket_type>> buckets;
Hash hasher;
bucket_type& get_bucket(Key const& key) const
{
std::size_t const bucket_index = hasher(key) % buckets.size();
return *buckets[bucket_index];
}
template <typename Key2, typename Value2>
friend std::ostream& operator<<(std::ostream& os, const thread_safe_hashmap<Key2, Value2>& map);
public:
thread_safe_hashmap(unsigned num_buckets = 19, Hash const& hasher_ = Hash())
: buckets(num_buckets), hasher(hasher_)
{
for (unsigned i = 0; i < num_buckets; ++i)
{
buckets[i].reset(new bucket_type);
}
}
thread_safe_hashmap(thread_safe_hashmap const& other) = delete;
thread_safe_hashmap& operator=(thread_safe_hashmap const& other) = delete;
void add_or_update_mapping(Key const& key, Value const& value)
{
get_bucket(key).add_or_update_mapping(key, value);
}
};
template <typename First, typename Second>
std::ostream& operator<<(std::ostream& os, const std::pair<First, Second>& p)
{
os << p.first << ' ' << p.second << '\n';
return os;
}
template <typename Key, typename Value>
std::ostream& operator<<(std::ostream& os, const thread_safe_hashmap<Key, Value>& map)
{
for (unsigned i = 0; i < map.buckets.size(); ++i)
{
for (const auto el : map.buckets[i]->data) os << el << ' ';
os << '\n';
}
return os;
}
int main()
{
thread_safe_hashmap<std::string, std::string> map;
map.add_or_update_mapping("key1", "value1"); // problematic line
std::cout << map;
}
The marked line is causing problems on both gcc and clang:
clang++ -Wall -std=c++14 main2.cpp -lboost_system -o main
main2.cpp:24:14: error: no viable conversion from returned value of type 'std::_List_const_iterator<std::pair<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> > >' to function
return type 'bucket_iterator' (aka '_List_iterator<std::pair<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> > >')
return std::find_if(data.begin(), data.end(),
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
main2.cpp:32:37: note: in instantiation of member function 'thread_safe_hashmap<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char>, std::hash<string> >::bucket_type::find_entry_for'
requested here
bucket_iterator found_entry = find_entry_for(key);
^
main2.cpp:71:21: note: in instantiation of member function 'thread_safe_hashmap<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char>, std::hash<string>
>::bucket_type::add_or_update_mapping' requested here
get_bucket(key).add_or_update_mapping(key, value);
^
main2.cpp:98:7: note: in instantiation of member function 'thread_safe_hashmap<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char>, std::hash<string> >::add_or_update_mapping'
requested here
map.add_or_update_mapping("key1", "value1");
^
/usr/bin/../lib/gcc/x86_64-linux-gnu/5.3.1/../../../../include/c++/5.3.1/bits/stl_list.h:125:12: note: candidate constructor (the implicit copy constructor) not viable: no known conversion from
'std::_List_const_iterator<std::pair<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> > >' to 'const std::_List_iterator<std::pair<std::__cxx11::basic_string<char>,
std::__cxx11::basic_string<char> > > &' for 1st argument
struct _List_iterator
^
/usr/bin/../lib/gcc/x86_64-linux-gnu/5.3.1/../../../../include/c++/5.3.1/bits/stl_list.h:125:12: note: candidate constructor (the implicit move constructor) not viable: no known conversion from
'std::_List_const_iterator<std::pair<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> > >' to 'std::_List_iterator<std::pair<std::__cxx11::basic_string<char>,
std::__cxx11::basic_string<char> > > &&' for 1st argument
1 error generated.
melpon's online demo
What am I missing here?
This is the expected behavior. In find_entry_for you're trying to return const_iterator, which doesn't match the return type iterator.
find_entry_for is const member function, for data.begin(), data will be const std::list<bucket_value>, begin() called on it will return const_iterator. And std::find_if will return the same type with the type of the parameter iterator, i.e. const_iterator, which could not be implicitly converted to the return type of find_entry_for, i.e. bucket_iterator (std::list::iterator).
Because the returned iterator might be used to change the value it points to, you could
Change find_entry_for to non-const member function. (Or add it as new overloading function, change the original const member function's return type to const_iterator.)
Try to convert const_iterator to iterator before returns.
bucket_iterator is defined the following way
typedef typename bucket_data::iterator bucket_iterator;
That is it is not a constant iterator.
However in member function find_entry_for
bucket_iterator find_entry_for(const Key& key) const
{
return std::find_if(data.begin(), data.end(),
[&](const bucket_value& item) { return item.first == key; });
}
standard algorithm std::find_if uses the constant iterator because this member function is declared with qualifier const and there are used overloaded functions begin and end for the constant data member data.
So you need to define the constant iterator in the class and use it as the return type of the function.
For example
typedef typename bucket_data::const_iterator const_bucket_iterator;
I am trying to use blitz++ arrays, since I understand they generally offer higher performance than other forms of arrays. Is it possible to use blitz++ arrays as keys in a map? Trying
#include <map>
#include <blitz/array.h>
using namespace std;
map<blitz::Array<int,1>,int> testmap;
blitz::Array<int,1> B(3);
B = 1,2,3;
testmap.insert(make_pair(B,2));
does not compile. Here's the error:
In file included from /usr/include/c++/4.6/string:50:0,
/usr/include/c++/4.6/bits/stl_function.h: In member function ‘bool
std::less<_Tp>::operator()(const _Tp&, const _Tp&) const [with _Tp =
blitz::Array]’:
/usr/include/c++/4.6/bits/stl_function.h:236:22: error: cannot convert
‘blitz::BzBinaryExprResult,
blitz::Array >::T_result {aka
blitz::_bz_ArrayExpr, blitz::FastArrayIterator, blitz::Less > >}’ to
‘bool’ in return
Is this a matter of requiring a definition of the < operator, and if so, can/should I define it myself?
ANSWER
As suggested by Jimmy Thompson, a possible solution is to define:
struct MyComparison
{
bool operator() (const blitz::Array<int, 1> &lhs, const blitz::Array<int, 1> &rhs) const
{
if (lhs.size() < rhs.size()) {return true;}
else if (lhs.size() > rhs.size()) {return false;}
else
{
for (int i=0; i<lhs.size(); i++)
{
if (lhs(i)<rhs(i)) {return true;}
else if(lhs(i)>rhs(i)) {return false;}
}
}
}
};
Then
map<blitz::Array<int,1>,int, MyComparison> testmap;
The std::map documentation states that keys are compared using std::less by default. This just calls < and expects a return of true or false.
In order for you to use Blitz arrays as a key, you need to do one of the following:
Create your own comparison function, like std::less, which returns a boolean value stating whether one Blitz array is 'less' than the other (how you choose to determine this is up to you). Assuming you made this function and called it MyComparison, you would then create your map as follows map<blitz::Array<int,1>, int, MyComparison> testmap;.
struct MyComparison
{
bool operator() (const blitz::Array<int, 1> &lhs, const blitz::Array<int, 1> &rhs) const
{
// Blitz array comparison
}
};
Wrap your Blitz array type (blitz::Array<int,1>) in another object, overloading the < operator for that given object and then performing your comparison in there. For example:
class MyArrayWrapper
{
blitz::Array<int, 1> contents;
public:
// Constructor, etc.
bool operator<(const MyArrayWrapper &rhs) const
{
// Blitz array comparison
}
};
Then in your current file.
std::map<MyArrayWrapper,int> testmap;
can't understand this: g++ compiler is angry on:
lengths.insert(pair<Deux,long>(d,one));
where
struct Deux {long big; long small};
map<Deux, long> lengths;
Deux d;
long one;
so, g++ said, that i miss operator<. after making overloaded operator< for struct Deux, i saw new interesting, but the same error:
map <long, Node*>ArrayOfNodes;
map <long, Node*>::iterator it;
for (it=ArrayOfNodes[Root]->nodes.begin();it<ArrayOfNodes[Root]->nodes.end();++it)
cout<<it->first<<endl;
also used structure Node:
struct Node {
long name;
long guest;
map <long,Node*>nodes;
/*bool operator<(const Node& node)const{
if ((*this).name<node.name) return true;
if ((*this).name>node.name) return false;
return (*this).guest<(*this).guest;
}*/
and error is:
no match for operator< in it < ((Path*)this)->Path::ArrayOfNodes.
std::map<_Key, _Tp, _Compare, _Alloc>::operator[] [with _Key = long int, _Tp = Node*,
_Compare = std::less<long int>, _Alloc = std::allocator<std::pair<const long int, Node*> >]
(((const long int&)((const long int*)(&((Path*)this)->Path::Root))))->Node::nodes.std::map<_Key, _Tp, _Compare, _Alloc>::end
[with _Key = long int, _Tp = Node*, _Compare = std::less<long int>, _Alloc = std::allocator<std::pair<const long int, Node*> >]()
The compiler complains that there is no operator < for Deux (I guess). The key must be a comparable class with operator < or you must pass a third template parameter to map - the comparator.
You see, the map keeps its keys in an ordered way. In order to order them, it needs a predicate. By default it tries to use operator <
try writing something like this:
bool operator < (Deux const & d1, Deux const & d2)
{
if(d1.big > d2.big)
return false;
if(d1.big < d2.big)
return true;
return d1.small < d2.small;
}
You did not mention the error message. Always post it!
So, I need to fork my post into two distinct sections.
Missing Declaration.
`error: 'Deux' was not declared in this scope`
That's because Deux is unknown at the point where you declare the map<>.
You need to declare Deux before map<Deux, long>, because map<Deux, long> requires the full definition of its parameters.
Missing Comparator.
`error: no match for 'operator<' in '__x < __y'`
That's because you haven't defined operator< for Deux.`
If you can define a logical operator<, i.e. one that is not arbitrarily chosen for sorting purposes, you could do it like this:
// must be in same namespace as Deux
bool operator< (Deux const &lhs, Deux const &rhs) {
return lhs.foo < rhs.foo;
}
If it needs access to non-public members, you can make it a member function:
bool operator< (Deux const &rhs) {
return this->foo < rhs.foo;
}
If such comparison would be arbitrary, do as Constantinius suggests.
Next time
You could have saved us time by posting your actual code or a minimal testcase, as well as by mentioning the error message.
My guess is that your struct is missing a compare function, to make an internal sorting of your Deux objects as keys. In a map, they have to be sorted.
This is the definition of std::map
template < class Key, class T, class Compare = less<Key>,
class Allocator = allocator<pair<const Key,T> > > class map;
So if you define a function like this:
bool compare_deux(Deux& a, Deux& b) {
return a.big < b.big;
}
and pass it as a template argument:
map <Deux, long, compare_deux> lengths;
you should be fine.
Use make_pair.
lengths.insert(make_pair<Deux,long>(d,one));
Just to add yet another reply, here's how I would implement Deux to be strictly ordered. We just use lexicographic ordering:
struct Deux
{
long big, small;
inline bool operator<(const Deux & o) const
{
return big < o.big || (!(o.big < big) && small < o.small);
}
};
std::map<Deux, T> m; // works now!
Alternatively, we could have spared ourselves the pain and said:
typedef std::pair<long, long> Deux;
std::map<Deux, T> m; // always works, lexicographic compare is provided by default
Always best not to reinvent the wheel!
Post a comment if you also want pair hashing using hash_combine to use unordered containers.
You need to declare the < operator or pass a comparison function on map creation.
struct Deux
{
long big;
long small
bool operator < (const Deux &n) const
{
if(big != n.big)
return big < n.big;
else
return small < n.small;
}
};
I can get a method of a class in a set iterator ?
#include <iostream>
#include <string>
#include <set>
class student{
public:
student(std::string n){
name=n;
}
void print(){
std::cout << name << std::endl;
}
bool operator < (const student & s1){ return true;}
bool operator = (const student & s1){ return true;}
private:
std::string name;
};
int main(){
std::set<student> studs;
studs.insert(student("name01"));
studs.insert(student("name02"));
std::set<student>::iterator it;
for(it = studs.begin(); it != studs.end(); it++)
(*it).print() ;
}
I get this error
students.cpp: In function ‘int main()’:
students.cpp:22: error: passing ‘const student’ as ‘this’ argument of ‘void student::print()’ discards qualifiers
/usr/include/c++/4.2.1/bits/stl_function.h: In member function ‘bool std::less<_Tp>::operator()(const _Tp&, const _Tp&) const [with _Tp = student]’:
/usr/include/c++/4.2.1/bits/stl_tree.h:982: instantiated from ‘std::pair<typename std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::iterator, bool> std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_M_insert_unique(const _Val&) [with _Key = student, _Val = student, _KeyOfValue = std::_Identity<student>, _Compare = std::less<student>, _Alloc = std::allocator<student>]’
/usr/include/c++/4.2.1/bits/stl_set.h:307: instantiated from ‘std::pair<typename std::_Rb_tree<_Key, _Key, std::_Identity<_Key>, _Compare, typename _Alloc::rebind<_Key>::other>::const_iterator, bool> std::set<_Key, _Compare, _Alloc>::insert(const _Key&) [with _Key = student, _Compare = std::less<student>, _Alloc = std::allocator<student>]’
students.cpp:18: instantiated from here
/usr/include/c++/4.2.1/bits/stl_function.h:227: error: passing ‘const student’ as ‘this’ argument of ‘bool student::operator<(const student&)’ discards qualifiers
with
bool operator<(const student & s1) const { return true;}
bool operator==(const student & s1) const { return true;}
now work!! O_o',
#include <iostream>
#include <string>
#include <set>
class student{
public:
student(std::string n){
name=n;
}
void print() const {
std::cout << name << std::endl;
}
bool operator<(const student & s1) const { return true;}
bool operator==(const student & s1) const { return true;}
private:
std::string name;
};
int main(){
std::set<student> studs;
studs.insert(student("name01"));
studs.insert(student("name02"));
std::set<student>::iterator it;
for(it = studs.begin(); it != studs.end(); it++)
it->print() ;
}
You need to add a const qualifer to your print member function:
void print() const
{
std::cout << name << std::endl;
}
Objects in an std::set are necessarily const, since they are used as keys. When an object (or reference) is constant, you can only call member functions of that object which are declared with the const qualifier.
You also want const qualifiers on both the == and < operator overload functions. (And don't forget to change = to == as pointed out in the comments.)
Yes, though it->print() is more intuitive.
A naive world-view is that iterators are a bit like pointers. There is more to it than that, as explained here.
The most obvious form of iterator is a
pointer: A pointer can point to
elements in an array, and can iterate
through them using the increment
operator (++). But other forms of
iterators exist. For example, each
container type (such as a vector) has
a specific iterator type designed to
iterate through its elements in an
efficient way.
You want operator==, not operator=.
Your operator< definition violates the requirements of std::set, and is inconsistent with your operator<. That is, according to your operator<, nothing is equivalent, but according to your operator==, everything is equal. Operator< should define a irreflexive, transitive, and asymmetric (for non-equivalent values) relation.
Objects in a set are necessarily const, and so to call a function on such an object that function must be declared with the const qualifier. Specifically, print() should be declared void print() const.
Similarly, operator< should be declared with the const qualifier. std::set requires that operator< can be called with const objects. Another valid option would be to make operator< a non-member function and to take both objects by value (bad) or const reference (good).
While not required in your example, operator== should also be declared with the const qualifier.
Write your print() function like this:
void print() const //<---- note this 'const'
{
std::cout << name << std::endl;
}
Now your code should work now. :-)
By the way, such functions with const keyword appearing on the right side, are called const member function, as they cannot change any member-data of the class.
See this FAQ: [18.10] What is a "const member function"?
#include <iostream>
#include <set>
using namespace std;
class Boxer{
public:
string name;
int strength;
};
struct Comp{
bool operator()(const Boxer& a, const Boxer& b){
return a.strength > b.strength;
}
};
int main(){
Boxer boxer[3];
boxer[0].name="uday", boxer[0].strength=23;
boxer[1].name="manoj", boxer[1].strength=33;
boxer[2].name="rajiv", boxer[2].strength=13;
set< Boxer, Comp> s;
s.insert(boxer[0]);
s.insert(boxer[1]);
s.insert(boxer[2]);
set< Boxer, Comp>::iterator it = s.begin();
Boxer b = *it;
cout<<b.name;
//result is Manoj
return 0;
}
I wrote a piece of code and used map and vector but it shows me something I can't get. I'll be thankful if someone help me in this way and correct my code or give me some hints.
The code is:
// For each node in N, calculate the reachability, i.e., the
// number of nodes in N2 which are not yet covered by at
// least one node in the MPR set, and which are reachable
// through this 1-hop neighbor
std::map<int, std::vector<const NeighborTuple *> > reachability;
std::set<int> rs;
for (NeighborSet::iterator it = N.begin(); it != N.end(); it++)
{
NeighborTuple const &nb_tuple = *it;
int r = 0;
for (TwoHopNeighborSet::iterator it2 = N2.begin (); it2 != N2.end (); it2++)
{
TwoHopNeighborTuple const &nb2hop_tuple = *it2;
if (nb_tuple.neighborMainAddr == nb2hop_tuple.neighborMainAddr)
r++;
}
rs.insert (r);
reachability[r].push_back (&nb_tuple);
}
/*******************************************************************************/
//for keepping exposition of a node
std::map<Vector, std::vector<const NeighborTuple *> > position;
std::set<Vector> pos;
for (NeighborSet::iterator it = N.begin(); it != N.end(); it++)
{
NeighborTuple nb_tuple = *it;
Vector exposition;
pos.insert (exposition);
position[exposition].push_back (&nb_tuple);
}
and the errors are for this line: position[exposition].push_back (&nb_tuple);
and the errors are:
/usr/include/c++/4.1.2/bits/stl_function.h: In member function ‘bool std::less<_
Tp>::operator()(const _Tp&, const _Tp&) const [with _Tp = ns3::Vector3D]’:
/usr/include/c++/4.1.2/bits/stl_map.h:347: instantiated from ‘_Tp& std::map<_K
ey, _Tp, _Compare, _Alloc>::operator[](const _Key&) [with _Key = ns3::Vector3D, _Tp = std::vector<const ns3::olsr::NeighborTuple*, std::allocator<const ns3::olsr::NeighborTuple*> >, _Compare = std::less<ns3::Vector3D>, _Alloc = std::allocator<std::pair<const ns3::Vector3D, std::vector<const ns3::olsr::NeighborTuple*, std::allocator<const ns3::olsr::NeighborTuple*> > > >]’
../src/routing/olsr/olsr-routing-protocol.cc:853: instantiated from here
/usr/include/c++/4.1.2/bits/stl_function.h:227: error: no match for ‘operator<’ in ‘__x < __y’
debug/ns3/ipv6-address.h:432: note: candidates are: bool ns3::operator<(const ns3::Ipv6Address&, const ns3::Ipv6Address&)
debug/ns3/nstime.h:475: note: bool ns3::operator<(const ns3::Time&, const ns3::Time&)
debug/ns3/ipv4-address.h:305: note: bool ns3::operator<(const ns3::Ipv4Address&, const ns3::Ipv4Address&)
debug/ns3/address.h:231: note: bool ns3::operator<(const ns3::Address&, const ns3::Address&)
debug/ns3/type-id.h:376: note: bool ns3::operator<(ns3::TypeId, ns3::TypeId)
Thanks in advance.
Bahar
std::map is a sorted container of pairs. As such, keys in the map must have operator <() defined. Make sure Vector has the less-than operator defined.
For example:
class Vector {
int len, ang;
friend bool operator<(const Vector&, const Vector&);
};
bool operator<(const Vector& v1, const Vector& v2)
{
return true_if_v1_is_less_than_v2(); // you define what "less than" means
}
Of course, there other ways to do this. You may make operator< a member function. Or you may have the two member data public and the operator a non-member, non-friend function. Or you may define operator< in an anonymous namespace, to enhance information hiding. Or you may use a comparator other than operator<.
You declared the position object as followed : std::map<Vector, std::vector<const NeighborTuple *> > position;
And you are trying to push NeighborTuple * inside...
Try using const NeighborTuple *
I notice that you seem to have a pushback line that compiles and a line that does not.
The difference might be that you have a const in the first case
NeighborTuple const &nb_tuple = *it;