I have an issue on returning an item from a std::map residing inside a class.
I am trying to create a simple function like
ExplorerObjectMapItem* MyClass::getFirst()
{
mInternalMapIterator = mObserverLookup.begin();
ExplorerObjectMapItem* item = &*mInternalMapIterator;
return item;
}
where the following typedefs are used
typedef map< Subject*, shared_ptr<ExplorerObject> > ExplorerObjectMap;
typedef pair<Subject*, shared_ptr<ExplorerObject> > ExplorerObjectMapItem;
typedef ExplorerObjectMap::iterator ExplorerObjectIter;
and the map and iterator are class members:
ExplorerObjectMap mObserverLookup;
ExplorerObjectIter mInternalMapIterator;
The above code for the getFirst() function gives a compile error saying
E2034 Cannot convert 'pair<Subject * const,boost::shared_ptr<ExplorerObject>
> *' to 'ExplorerObjectMapItem *'
Not sure what is going on here. Any help appreciated.
A std::map<K,V> does not contain std::pair<K,V> objects. It contains std::pair<const K, V> objects. That missing const is what throws off the conversion.
You could fix this with either
typedef pair<Subject* const, shared_ptr<ExplorerObject> > ExplorerObjectMapItem;
or
typedef ExplorerObjectMap::value_type ExplorerObjectMapItem;
Related
I have a map of structs that holds several named values like this:
struct MyData {
MyType dataA;
std::string dataB;
int dataC;
};
typedef std::pair<std::string, MyData> PairType;
std::map<PairType::first_type, PairType::second_type> dataMap;
This is defined in a header file of a compilation unit that calls a function from a library.
Because the library function does not know about my type definitions, I can't pass dataMap directly.
The function only actually needs the dataA struct member and already knows about MyType, so I could pass a std::map<std::string, MyType> instead.
Whats the most elegant way of cutting just the data I need from the map of structs and save it into a new map with the same keys but only the type and values from dataA?
Preferably for C++0x without usage of boost or other external libraries, but solutions for newer standards are also welcome for educational purposes.
I'm basically looking for an equivalent of Python's
newDict = {key:value.dataA for (key,value) in oldDict.items()}
You can use a ranged based for loop to really easily make a copy. That would look like
std::map<std::string, MyType> my_type_map;
for (const auto& pair : dataMap)
{
my_type_map.emplace(pair.first, pair.second.dataA);
}
If you want this as a single expression, you are going to need something like boost::transform_iterator, either by including that, or writing an iterator yourself.
Given a conversion function (or equivalent lambda)
std::pair<std::string, MyType> convert(PairType& pair){
return { pair.first, pair.second.dataA };
};
You can declare newDict and populate it
/* can be const */ std::map<std::string, MyType> newDict {
boost::make_transform_iterator(oldDict.begin(), convert),
boost::make_transform_iterator(oldDict.end(), convert)
};
Or you can use a view type
auto newDict = boost::copy_range<std::map<std::string, MyType>>(oldDict | std::ranges::views::transform(convert));
This code compiles successfully with VS, but when porting it to Linux and compiling with g++ it errors out.
template <class Key, class Value>
void Dictionary<Key, Value>::set(const Key &key, Value value)
{
typename Dictionary<Key,Value>::iterator i = this->find(key);
if (i == this->end())
{
access(&key, &value, eINSERT);
this->insert(value_type(key, value));
}
else
{
access(&key, &i->second, eCLEAR);
dispose(i->second);
access(&key, &value, eSET);
i->second = value;
}
}
template <class Key, class Value> class PtrDictionary : public Dictionary<Key, Value>;
class Processor
{
private:
ptrdictionary<const string,const type*> m_Types;
void Processor::add(const string name, const Type* t)
{
if (m_Types.get(name))
error("Type '"+string(name)+"' already defined", eParseError);
m_Types.set(name, t); // this is where the error is received
}
}
The error is:
../Packages/Dictionary.h: In instantiation of 'void Dictionary::set(const Key&, Value) [with Key = const
std::basic_string; Value = const AsmLoader::Type*]':
Instructions.cpp:94:21: required from here
../Packages/Dictionary.h:79:37: error: expected primary-expression
this->insert(value_type(key, value));
Update:
value_type is an object in std::map, and all it took for g++ to compile the code was to add this:
typedef typename map<const Key, Value>::value_type value_type;
Thanks everyone for your comments, this is my first time using SO and this is a very complex code so I forgot to specify this part...
Unfortunately, it does not look as if this can be implemented in the same fashion as in VS. In researching this, I found:
Can dictionaries be used in c++
They suggested using std::map in STL as a similar method in C++ (without .NET). In case the above link changes, here is a quote from the answer supplied:
There is a corresponding type in STL, that's called std::map.
It has the same basic functionality as a .NET Dictionary, but the
implementation is quite different. std::map is internally based on a
red-black tree datastructure, while Dictionary uses a hash table
internally.
If you're just looking for something with the same behaviour, std::map
will do, but if you have large amounts of data you have to be aware of
the different performance characteristics.
** Caveat - I am still learning, so apologies if this is off the mark of your original question. Hope this helps!
Resolved!
value_type is an object in std::map, and all it took for g++ to compile the code was to add this:
typedef typename map<const Key, Value>::value_type value_type;
I have stumbled upon some weird use of priority_queue, I would love to obtain some proper explanation of why on earth it's plausibile/valid to use something like this in priority_queue declaration:
typedef priority_queue<RandomContainer, **vector<RandomContainer>**, FunctorName> NewQueueName;
Let's say we've got some struct called SPerson:
struct SPerson
{
int age;
string name;
string surname;
};
and some functor which will be helpful to sort all elements of queue accordingly to our likeing:
struct TheWayILike
{
bool operator()(const SPerson &name1, const SPerson &name2)
{
if(name1.name > name2.name) return true;
if(name1.name < name2.name) return false;
return false;
}
};
Now we can declare our priority_queue which will be based upon elements from the struct and which will be ordered by functor called TheWayILike.
priority_queue<SPerson, TheWayILike>
or shorter way by using typedef and single name like so:
typedef priority_queue<SPerson, TheyWayILike> newNameForPQ;
but somehow it's wrong and I have to add following line: vector
Question:
Why on earth do I have to squize my personally customized data types into vector ?
Why it must be a vector and why should I use it anyway ?
Why do I need to fill my data into vector ? I haven't read about it in official priority_queue documentation, so I would love to obtain some easy to understand explanation for rookie programmer.
Cheers!
You dont' have to. But look at the declaration of the priority_queue class template:
template<
class T,
class Container = std::vector<T>,
class Compare = std::less<typename Container::value_type>
> class priority_queue;
You can't provide a custom comparator type argument unless you also provide the underlying container to hold the data in. The author of the line above decided vector was the best choice. Any other container that fits the requirements can also be used, e.g. deque, but vector proves to be best for most applications so it is the default.
To take apart a pair, the following can be done
boost::bind(&std::pair::second, _1); // returns the value of a pair
What about using combinations of different containers, how can a nested pair be accessed?
For example when I wanted to partition a vector into items contained in a supplemental map and items that where not contained in the supplemental map I used the following:
typedef int DWORD; typedef std::pair<std::string, bool> user_info;
typedef std::map<DWORD, user_info> USER_MAP;
typedef std::vector<DWORD> VEC_STAFF;
VEC_STAFF::iterator it = std::partition(
Staff.begin(), Staff.end(),
(bind(&USER_MAP::find, m_Users, _1) != m_Users.end()));
Now I have a second problem - during the running of the application the status bool of user_info can change, and later on I want to re-partition the vector with items that have a status bool of true rather than just being contained in the supplemental map.
However I seem to have a problem accessing the second item of a nested pair.
I tried the following but I cannot seem to access the nested pair!
VEC_STAFF::const_iterator itCurEnd = partition(Staff.begin(), Staff.end(),
bind(&USER_MAP::value_type::second::second,
bind(&USER_MAP::find, &m_Users, _1)) == true);
Not sure I follow what's going on there, but usually when I start running into problems with bind I give up and implement a functor. This might simplify things in your case.
To me, the following is a lot easier to read than all that messing around with multiple levels of binds
template <class Arg>
struct Whatever : public std::unary_function<Arg, bool>
{
bool operator()(const Arg &arg1) const {
//logic here
}
};
Whatever<???> functor;
std::partition(Staff.begin(), Staff.end(), functor);
The syntax you used obviously doesn't work. The first "::second" already signifies a non-static member and not a type. If you have a pair inside a pair you probably have to use two bind calls:
typedef std::pair< int, bool > foo_t;
typedef std::pair< int, foo_t > bar_t;
.....
bind( &foo_t::second, bind(&bar_t::second,
bind( &USER_MAP::find, _1 )
) )
(I didn't test this. Perhaps this is what you want)
But three levels if bind is quite challenging, in my opinion.
Edit: How about this?
template<typename Iter, typename Return>
struct deref_2nd_2nd : std::unary_function<Iter, Return> {
Return operator()(Iter const& it) const {
return (*it).second.second;
}
};
.....
bind(
deref_2nd_2nd<USER_MAP::iterator,bool>(),
bind( &USER_MAP::find, _1 )
)
I'm trying to return an iterator for a vector in a templated class (I'm not sure if that makes a difference, but I've read that may, so I thought I'd mention it). The problem is that I get an error about C++ not supporting default-int when I try this. I've looked online and from what I can see in forums and explanaions, I don't think I'm that far off, it just won't compile.
template<class T>
class Table
{
public:
...
vector<shared_ptr<vector<T>>>::iterator GetRowIterator();
//vector<shared_ptr<vector<CellValueType> > >::const_iterator GetRowIterator();
...
protected:
vector<shared_ptr<vector<CellValueType> > > data; //outside vector is rows, inside vector is columns
...
};
vector<shared_ptr<vector<T> > >::const_iterator Table<T>::GetRowIterator()
{
return data.begin();
}
The errors that I get are:
error C2146: syntax error : missing ';' before identifier 'GetRowIterator'
error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
Edit:
Changed the end angle brackets so they are not as close together - same error.
Any thoughts as to why this is occurring?
As always, thanks for advice/help in advance!
Also remember to use typename when declaring the template-dependent return type:
typename vector< shared_ptr< vector< T > > >::iterator GetRowIterator();
and the method definition
typename vector< shared_ptr< vector< T > > >::const_iterator Table<T>::GetRowIterator()
{
return data.begin();
}
Notice also that when defining a template class method outside the class definition, you have to use the template keyword:
template <class T> typename vector< shared_ptr< vector< T > > >::const_iterator Table<T>::GetRowIterator()
{
return data.begin();
}
So that the compiler can know what the T is about.
This part here:
vector<shared_ptr<vector<T>>>
It is a problem with the C++ syntax you can not put >> together like that.
vector<shared_ptr<vector<T> > >
This is a problem that is being addressed by the new standard.
Because the lexer is the first stage of the compiler it sees the >>> as a shift left operator followed by >. Thus you are getting syntax errors in your code. To supress this problem you just need to add white space between the > when closing templates.