I am trying to store objects in a boost multi-index container.
These objects are all unique can be retrieved by 2 separate keys (unique as well).
namepsace bm = boost::multi_index;
class MyObj {
string strid_;
int32_t numid_;
};
//! associative container searchable by ClOrdId and Sunofia Id.
typedef boost::multi_index_container< MyObj,
bm::indexed_by<
bm::ordered_unique<
bm::member<MyObj,string,&MyObj::strid_>
>,
bm::ordered_unique<
bm::member<MyObj,int32,&MyObj::numid_>
>
>
> Cntr;
Cntr cntr_;
When I try to find any element of that index by integer I use the following code
int32_t to_find = 12;
Cntr::iterator it = cntr_.find(id);
but it doesn't compile and I get the following error
error: invalid conversion from ‘int’ to ‘const char*’
When I use the same code with string it works fine; do you know what I am doing wrong?
auto it = cntr_.get<1>().find(id);
Each index is accessed separately (via get) and has its own member functions, iterators, etc. (In case you can't use auto,it is of type Cntr::nth_index<1>::type::iterator.) More info on the doc tutorial.
Related
I have the following map:
std::map<my_msgs::Nodelet, int> mRunningProcPID;
When trying to insert a new pair to the map I am getting the following error:
error: no match for ‘operator<’ (operand types are ‘const my_msgs::Nodelet_<std::allocator<void> >’ and ‘const my_msgs::Nodelet_<std::allocator<void> >’)
{ return __x < __y; }
I get it that I need to override the < operator for my_msgs::Nodelet, the problem is that I do not have access to that h file since it is being auto generated by ROS.
Any idea what can I do?
The problem is that std::map will attempt to index the mapped elements, and it doesn't know how to index my_msgs::Nodelet because it doesn't know how to compare this object.
You have to provide a third parameter when declaring this map, with a Compare function, or implement the necessary interface (handler for operator <) for it to use the default comparison method.
But you can also avoid this trouble by just using std::unordered_map instead.
std::unordered_map will do pretty much the same thing std::map does but it doesn't bother to index the elements. This approach is also considered faster in many cases.
Any idea what can I do?
Option 1: Use a non-member function to compare two Nodelet objects.
You can define a non-member function operator< between two Nodelet objects with the following signature.
bool operator<(my_msgs::Nodelet const& lhs, my_msgs::Nodelet const& rhs);
You don't need the ability to modify the class to do that. You can declare it in your own .h file and define it in your own .cpp file.
Option 2: Use a functor to compare two Nodelet objects
You can define a functor with the following interface:
struct CompareNodelet
{
bool operator()(my_msgs::Nodelet const& lhs, my_msgs::Nodelet const& rhs) const;
};
and use it to construct the map.
std::map<my_msgs::Nodelet, int, CompareNodelet> mRunningProcPID;
The documentation for Boost multiindex containers seem to indicate that I can use it as a set after declaring an index to iterate over. So I was wondering if it is possible to hide the boost implementation and return an iterator masqueraded as an iterator to an std::set
Ex: Header
typedef multi_index_container<
Employee,
indexed_by<
ordered_non_unique<
composite_key<
Employee,
member<Employee, int, &Employee::id>,
member<Employee, int, &Employee::salary>
>
>
> > EmployeeSet;
const std::set<Employee>::iterator getEmployees();
static EmployeeSet employeeSet;
Test.cc:
const std::set<Test::Employee>::iterator getEmployees(){
std::pair<EmployeeSet::iterator, EmployeeSet::iterator> by_id =
employeeSet.equal_range(id);
return by_id.first;
}
Is it possible to do something like this? and How?
No, you can't. The EmployeeSet you have defined works like a std::set (a std::multiset, actually), but it is not one. The iterator types of these unrelated containers are different and you can't pass one as the other.
Maybe you can reconsider why you need to pass an iterator to an index of a multi_index_container as a std::set::iterator.
Bear with me please, this is my first time posting. I have 3 classes. Class Suppliers has a set of Class Parent. Class Parent has a vector of Class location and Class location has data memebers. Ex (this is pseudo code, not my actual code. I've only shown this for simplicity sake):
Class Suppliers{
set<Parent> setter;
};
Class Parent{
vector<location> loc;
};
`
The following is the a constructor of the location class I created. I run into no problems until lines I hit the two lines with the iterators. I am trying to find a specific Parent and push back a new location onto the Parent 'loc' vector. So I pass in the iterator I've found previously as a reference. But as soon as I try to push back the new instance of my location class I get the following error.
data.cpp:139:33: error: passing 'const std::vector' as 'this' argument of 'void std::vector<_Tp, _Alloc>::push_back(const value_type&) [with _Tp = location; _Alloc = std::allocator; std::vector<_Tp, _Alloc>::value_type = location]' discards qualifiers [-fpermissive]
The last line also gives an error that says I cannot alter a read-only object. I'm confused as to why this would be a read only object. I did some research and thought that I needed to add a copy constructor. However, that caused more problems than it solved. Any ideas?
location::location(set<Parent>::iterator &it, vector<string> v){
sup_id = v[0];
address1 = v[2];
address2 = v[3];
city = v[4];
state = v[5];
country = v[6];
zip = v[7];
((*it).loc).push_back(*this);
((*it).num)++;
}
The problem is that a set is sorted. If you'd be allowed to change an element through the iterator, it would basically mean that you could potentially invalidate the iterator and therefore since C++11, the iterator of a set is a constant bidirectional iterator and thereby has the same semantics as the set's const_iterator.
The solution, although slightly ugly, is to remove, modify and re-insert the element. There is a proposal to allow modification of the keys of associative containers, but I don't know if there is any progress in getting it standardized.
I'm trying to create an iterator which only can dereference to real value types, not to references.
Is this possible using boost::iterator_facade, or does it require me to have values that can be returned by adress\reference.
To be more specfic, my iterator returns a std::pair of references, which means my iterators value_type is not stored anywhere, but created on the fly on dereferencing (like std::map::iterator).
Yes, thing you want is possible. Please, take a look at boost/iterator_facade.hpp (example is for Boost lib of version 1.49.0 but it is ok for its new distributions also):
template <
class Derived
, class Value
, class CategoryOrTraversal
, class Reference = Value&
, class Difference = std::ptrdiff_t
>
class iterator_facade
Template argument Reference is the key. You should just specify Reference when deriving from boost::iterator_facade. For example, your code can look like as the following:
template<typename value_type>
class custom_iterator
: public boost::iterator_facade<
custom_iterator<value_type>,
value_type,
boost::forward_traversal_tag,
value_type
>
{
...
value_type dereference() const{ return value_type(...); }
...
};
There is a struct which contain intrusive_ptr field:
struct BranchFeedback : boost::counted_base {
...
boost::intrusive_ptr<BPredState> theBPState;
};
There is another varibale which is defined as
std::vector< std::vector< BPredState > > theFetchState;
Now I have instantiated an object
BranchFeedback theFeedback;
and want to assign theFetchState to that field
theFeedback.theBPState = theFetchState[anIndex][!anOne];
However compiler says some errors
error: no match for ‘operator=’ in theFeedback.theBPState = .....
How can I fix that?
you're passing in a BPredState, but intrusive_ptr only supports operator= for pointers to the contained type (or other intrusive_ptrs)
so you could write theBPState = &(theFetchState[anIndex][!anOne]); or get an pointer or iterator to the element and use that instead.