C++ Map can't insert with pair - c++

Why can't I insert as shown below?
#include <map>
struct something {
} some_object;
typedef std::map<std::string, something*> list;
typedef std::pair<std::string, something*> pair;
int main()
{
list l;
pair p("abc", &some_object); // working fine!!!
l.insert(p); // 17 errors
return 0;
}
Visual studio gives me many errors and I don't understand anything of them. The first one is:
error C2784: 'bool std::operator <(const std::_Tree<_Traits> &,const std::_Tree<_Traits> &)' : could not deduce template argument for 'const std::_Tree<_Traits> &' from 'const std::string'
I can post more but I don't want to spam here. Thanks a lot for your help.

You need to
#include <string>

I would change this line:
typedef std::pair<std::string, something*> pair;
You are relaying on an implementation detail. Are you sure this wil always be true for all future version of the library? Tightly coupling your code like that is a bad idea.
Try this:
typedef list::value_type pair;
PS. 'list' would not be my first choice for the name of a type I put in the global namespace. Either put it in your own namespace or call it 'MyList'.

Related

Problems when using unordered_set as the key of unordered_map, in C++

The original problem is kind of long, so I simplify it here.
I need to create a group of strings, with a relevent integer, let's say a training group. Then I need to create many training groups. I want to manage all the training groups in a single container. So I decided to use boost::unordered_map<> with the key being std::unordered_set. Because, the BOOST has hash value for the standard C++ container.
The simplified code are as follows:
#include <string>
#include <unordered_set>
#include <utility>
#include<boost/unordered_map.hpp>
using namespace std;
int main()
{
boost::unordered_map< unordered_set<string>, int> training_groups;
pair<unordered_set<string>, int> a_training_group;
training_groups.insert(a_training_group);
return 0;
}
However, the code doesn't compile successfully. There are many cryptic warnings and an error. The error is as follows:
1>C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\xhash(30): error C2440: 'type cast' : cannot convert from 'const std::unordered_set<std::string,std::hash<_Kty>,std::equal_to<_Kty>,std::allocator<_Kty>>' to 'size_t'
1> with
1> [
1> _Kty=std::string
1> ]
1> No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
1> C:\Program Files\boost\boost_1_59_0\boost/functional/hash/extensions.hpp(262) : see reference to function template instantiation 'size_t stdext::hash_value<T>(const _Kty &)' being compiled
1> with
1> [
1> T=std::unordered_set<std::string,std::hash<std::string>,std::equal_to<std::string>,std::allocator<std::string>>
1> , _Kty=std::unordered_set<std::string,std::hash<std::string>,std::equal_to<std::string>,std::allocator<std::string>>
1> ]
I don't know where is the origin of this error and how to solve it. If the compiler cannot file the hash function of unordered_set, the error information will contains words like "Hash" or "Key". However, it just says something about type conversion, which looks similar to hash function. So, I feel confused.
Can anyone provide some advice. I am using Visual Studio 2013 on Windows 8.
PS: when I changed the Key unordered_set<string> to set<string> or vector<string>, the program compiles successfully. But I still don't know the reason, and don't know how to solve the problem if I am determined to use unordered_set<string> as the key.
Boost does not provide a hash function for std::unordered_set, the list of hash functions contains e.g. one for std::set:
http://www.boost.org/doc/libs/1_61_0/doc/html/hash/reference.html#idp6283424-bb
So you must provide your own hash function, which is relatively easy when using boost::hash_range:
#include <string>
#include <unordered_set>
#include <utility>
#include <boost/functional/hash/hash_fwd.hpp>
namespace boost
{
template <class K, class C, class A>
std::size_t hash_value(const std::unordered_set<K, C, A>& v)
{
return boost::hash_range(v.begin(), v.end());
}
} // namespace boost
#include <boost/functional/hash.hpp>
#include <boost/unordered_map.hpp>
int main()
{
boost::unordered_map<std::unordered_set<std::string>, int> training_groups;
std::pair<std::unordered_set<std::string>, int> a_training_group;
training_groups.insert(a_training_group);
return 0;
}
live example

std::map with an object as value

I have an error while trying to use std::map with my own class as value. The definition of the map is this:
std::map<std::string,CCrossSection> Xsects;
This line compiles fine (so it kindo of works?)
Xsects[sectionId].m_vProfile.push_back(pt);
When I try to iterate over the map however:
for (std::map<std::string,CCrossSection>::iterator xs = Xsects.begin(); xs < Xsects.end(); xs++) {
it->second.SaveFile(f);
}
It gives me multiple errors similar to this:
error C2784: 'bool std::operator <(const std::_Tree<_Traits> &,const std::_Tree<_Traits> &)' : could not deduce template argument for 'const std::_Tree<_Traits> &' from 'std::_Tree<_Traits>::iterator'
with
[
_Traits=std::_Tmap_traits<std::string,CCrossSection,std::less<std::string>,std::allocator<std::pair<const std::string,CCrossSection>>,false>
]
c:\program files\microsoft visual studio 9.0\vc\include\xtree(1466) : see declaration of 'std::operator <'
I thought that it is a problem with less operator and I added it to my definition of the class CCrossSection, but it didn't change a thing. Later I read that the key of the map has to have less operator defined and I think std::string has. Any ideas why it happens?
Cheers
Tomek
it will compile when you compare the end iterator with operator!=

std::find on std::vector< std::string > does not compile in Visual C++ 2008?

I tried this code on Visual C++ 2008 express edition, but it does not compile:
#include <iostream>
#include <vector>
#include <algorithm>
int main()
{
typedef std::string Element;
typedef std::vector< Element > Vector;
typedef Vector::iterator Iterator;
Vector v;
std::find( v.begin(), v.end(), std::string( "xxx" ) );
return 0;
}
I get the following error:
c:\programmi\microsoft visual studio 9.0\vc\include\algorithm(40) : error C2784: 'bool std::operator ==(const std::vector<_Ty,_Alloc> &,const std::vector<_Ty,_Alloc> &)' : could not deduce template argument for 'const std::vector<_Ty,_Alloc> &' from 'std::basic_string<_Elem,_Traits,_Ax>'
The same code is corrected compiled by gcc and works as expected.
Is it a bug of Visual Studio? And how can I get my example working on Visual C++ 2008?
You forgot to #include <string>.
You must always include all the headers that you need for your code. Never depend on magic recursive inclusions that happen to work sometimes. For everything you use in your code you must know where it has been declared and guarantee that the declarations are visible in your translation unit.

How to put std::set into std::map

I declared std: map below:
std::map<std::string, std::set<unsigned char*>> FilesMap;
int InsertData(unsigned char* name)
{
// here i try to insert pair with name above and clear std::set
FilesMap.insert(std::pair<std::string, std::set<unsigned char*>>(std::string((char*)name), std::set<unsigned char*>()));
}
But I have many errors like:
Error 16 error C2676: binary '<': 'const std::string' does not define
this operator or a conversion to a type acceptable to the predefined
operator c: \program files (x86)\microsoft Visual Studio
10.0\vc\include\xfunctional
What am I doing wrong?
First of all, this horribly long line
FilesMap.insert(std::pair<std::string, std::set<unsigned char*>>(std::string((char*)name), std::set<unsigned char*>()));
can be simplified if you use std::make_pair function, which will deduce template arguments.
FilesMap.insert(std::make_pair(std::string(reinterpret_cast<char*>name)), std::set<unsigned char*>()));
Second, you could make a typedef for your set so as to simplify the above line even more
typedef std::set<unsigned char*> mySetType;
std::map<std::string, mySetType>> FilesMap;
FilesMap.insert(std::make_pair(std::string(reinterpret_cast<char*>name)), MySetType()));
And lastly, and most importantly, I believe the reason that the compiler is unable to find a suitable operator < for std::string is that you forgot to #include<string>
A requirement for using std::map, is that the key type has to have an operator < . It seems you are getting an error with regards to std::string not having this operator. Make sure you have included the string header #include <string>.

C2784 using a set of iterators over map

the code below produces compiler error C2784:
'bool std::operator <(const std::_Tree<_Traits> &,const std::_Tree<_Traits> &)' : could not deduce template argument for 'const std::_Tree<_Traits> &' from 'const std::_Tree_iterator<_Mytree>'
What is wrong with the code? Many thanks in advance; I couldn't find any posts on that error message that would help me.
#include <map>
#include <set>
void main(){
int i=1;
std::map<int, int> A;
A[i]=i;
std::set<std::map<int, int>::iterator > setOfIts;
setOfIts.insert(A.begin());
}
What you're seeing is Visual Studio's long way of complaining it has no way to compare the iterators you'd like to place in the set, because there's no appropriate operator <. And since it can't compare them, it can't decide whether two iterators have the same value, hence only one of them should be in the set.
To fix the problem, you can provide a less then operator of your own - see example here. What would be the meaning of iterators equality is up to you to figure out...