I have written a sort class to sort the multimap, but when I insert element into the map, the following compiler error appears:
1>c:\program files\microsoft visual studio 9.0\vc\include\xutility(313) : error C2664: 'bool MapSort::operator ()(std::pair<_Ty1,_Ty2> &,std::pair<_Ty1,_Ty2> &)' : cannot convert parameter 1 from 'const std::pair<_Ty1,_Ty2>' to 'std::pair<_Ty1,_Ty2> &'
can anybody help?
class MapSort
{
public:
MapSort();
~MapSort();
public:
bool operator() ( pair<T,T>& i, pair<T,T>& j)
{
return i.first.GetID() < j.first.GetID();
}
};
multimap < pair < T,T >,P > CurrMap;
CurrMap.insert( multimap < pair < T, T >,Metric >::value_type(make_pair< T,T >(aAttractionA,aAttractionB),CurrP))
//
pair<T,T>& i and pair<T,T>& j
should be
pair<T,T> const& i and pair<T,T> const& j
(reference)
You forgot const-correctness:
bool operator()(pair<T,T> const& i, pair<T,T> const& j) const
{
return i.first.GetID() < j.first.GetID();
}
Nothing in this function needs to be mutable, so "why not" make the function and its inputs const?
In fact, this is expected of you by the contracts of the container.
In addition, I'm not sure that your own sort ordering here is valid or that it makes sense. It certainly doesn't seem entirely purposeful. pair<T,T> already sorts naturally: if anything, you might have a bool operator< for your type T.
Your sort predicate must take const references.
Plus, aren't multi-maps already sorted?
Related
when I try to insert in this map:
std::map<std::unordered_set<int >, std::pair<float, std::pair<float, float >> >
I got this error
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::unordered_set,std::equal_to<_Kty>,std::allocator<_Kty>>'
My data is defined as follows:
struct Trans {
int Item;
float Prob;
float W;
};
bool operator<(const Trans &a, const Trans &b)
{
return a.Item < b.Item;
}
bool operator==( Trans c, Trans d) { return c.Item == d.Item; }
struct MyHash {
size_t operator()(const Trans& x) const { return std::hash<int>()(x.Item); }
};
std::vector<std::vector<Trans>> data;
std::map<std::unordered_set<int>, float> S1;
std::map<std::unordered_set<int >, std::pair<float, std::pair<float, float >> > S2;
std::map<std::unordered_set<int >, std::pair<float, std::pair<float, float >> > S3;
The part that has the problem:
do
{
std::unordered_set<Trans, MyHash> KS(data[i].begin(), data[i].begin() + k);
std::unordered_set<int > elem;
float esupp = 1;
float Weight = 0;
float Wesupp = 1;
for (auto const &iter : KS)
{
elem.insert(iter.Item);
esupp *= iter.Prob;
Weight += iter.W;
}
Weight = Weight / k;
/*
some code, and until here I didn't get any problem
*/
**// This the area that has the problem**
S1[elem] = std::move(S1[elem] + esupp);
Wesupp = Weight * S1[elem];
S2[elem].first = std::move(S2[elem].first + esupp);
S2[elem].second = std::make_pair(elem, Wesupp);
} while (next_combination(data[i].begin(), data[i].begin() + k, data[i].end()));
A std::map expects its key to implement the operator <, unless a comparator is supplied.
Your key type, std::unordered_set doesn't implement "less than".
As #T.C. mentions, you could use std::set instead of std::unordered_set.
Your current error, as Drew Dormann pointed out, is caused by std::unordered_set's lack of an operator <.
std::set, however, does have an overloaded operator <, so you can use that.
The problem with your code runs deeper than that, though. For instance:
S1[elem] = std::move(S1[elem] + esupp);
You are assigning a float. There's absolutely no point in using std::move, especially as S1[elem] + esupp is already an rvalue. The usual way of writing this line would be S1[elem] += esupp;
S2[elem].first = std::move(S2[elem].first + esupp);
Same problem.
S2[elem].second = std::make_pair(elem, Wesupp);
The LHS of the assignment is a std::pair<float, float>; the RHS creates a std::pair<std::unordered_set<int>, float>.
And as I mentioned in the comments, std::pair<float, std::pair<float, float>> is just bad design. It should be at least std::tuple or even better a std::array<float, 3> or even better a simple struct that makes clear what each of the three floats actually mean.
Further, using a set<int> (unordered or not) as a key in a map is a fairly weird design. Do you want to just maintain a list of set<int>-3xfloat pairings that you can iterate through, or do you actually want to be able to efficiently index with a set<int>? If you don't need the efficient indexing, just use a vector of pairs rather than a map.
vector< pair<size_t, tuple<double,double> >>
sort_indexes(const vector<tuple<double,double>> &v)
//takes a list and prepends the sorted inxdex
{
// Copy data
vector< pair<size_t, tuple<double,double> >> idx(v.size());
for (size_t i = 0; i != idx.size(); ++i)
{
idx[i].first=i ;
idx[i].second=v[i];
}
sort(idx.begin(), idx.end(),
[&v](size_t i1, size_t i2) {return get<0>(v[i1]) < get<0>(v[i2]);}
);
return idx;
}
The error looks like:
1>C:\Program Files (x86)\Microsoft Visual Studio
11.0\VC\include\algorithm(3781): error C2664: 'bool sort_indexes::::operator
()(size_t,size_t) const' : cannot convert parameter 1 from
'std::pair<_Ty1,_Ty2>' to 'size_t'
I'm confused, what is the form of the comparator? I think that it should be anything that returns a boolean? and the lambda I supplied seams to return a boolean?
When I remove the comparator the code still sorts, although this effect isn't desired as sort by the index has a predictable outcome.
You are trying to sort a vector< pair<size_t, tuple<double,double> >>, so the comparator must compare pair<size_t, tuple<double,double> >, not size_t.
simple try it in gcc-4.9, get the below information:
no known conversion for argument 1 from 'std::pair >' to 'size_t {aka long unsigned int}'
simply conclusion: your comp is not correct, you need a comparator of std::pair<size_t, std::tuple<double, double>>.
for here, sort
comp - comparison function object (i.e. an object that satisfies the requirements of Compare) which returns true if the first argument is less (i.e. is ordered before) the second element.
The signature of the comparison function should be equivalent to the following:
bool cmp(const Type1 &a, const Type2 &b);
The signature does not need to have const &, but the function object must not modify the objects passed to it.
The types Type1 and Type2 must be such that an object of type RandomIt can be dereferenced and then implicitly converted to both of them.
The type of Type1 and Type2 is pair<size_t, tuple<double,double> > in your code.
Comparator should be (if sorting by indices):
typedef pair<size_t, tuple<double,double> > param;
sort(idx.begin(), idx.end(), [&v](const param &it, const param &jt) {
return it.first < jt.first;
});
Otherwise:
typedef pair<size_t, tuple<double,double> > param;
sort(idx.begin(), idx.end(), [&v](const param &it, const param &jt) {
return std::get<0>(it.second) < std::get<0>(jt.second);
});
I have a function template that takes a vector and an element of a given type and returns the position of the element in the vector. This is the code for this function template:
template<class T>
int findElement(const vector<T> &vec, const T &ele)
{
for(size_t i = 0; i < vec.size(); i++)
{
if(ele == vec[i])
return i;
}
return -1;
}
And here's the function call:
findElement<double>(intVec, ele);
But I get this error when I call the function:
error C2664: 'findElement' : cannot convert parameter 1 from 'std::vector<_Ty>' to 'const std::vector<_Ty,_Ax> &'
And this error is same even if I remove the const for the vector in the function template definition:
error C2664: 'findElement' : cannot convert parameter 1 from 'std::vector<_Ty>' to 'std::vector<_Ty,_Ax> &'
However, when I make the function call as
findElement(intVec, ele)
I do not get any error.
What is the reason for this behavior?
Seems like compiler cannot convert vector<double> to vector<int>. Since by logic way, intVec is vector of ints, isn't it? And you say compiler, that you want vector of doubles.
You cannot convert vector<T> to vector<U>, since vector has no following conversion constructor, and it's nice.
I'm trying to get the includes algorithm to work on a set and map by comparing the map's keys to the set's values. The issue that needs to be circumvented is of course that map<K,V>::value_type is pair<K,V> while set<V>::value_type is V so these are not going to work with the default includes predicate<T> which expects the same value type for both arguments.
I am hence writing the below predicate classes to get around this
template <class P,class K>
struct mapKey_set_less : public std::binary_function<P,K,bool>
{
inline bool operator() (const P& x, const K& y) const {return x.first < y ;};
};
template <class K,class P>
struct set_mapKey_less : public std::binary_function<K,P,bool>
{
inline bool operator() (const K& x, const P& y) const {return x < y.first ;};
};
However the template instantiator is throwing up on line 313 of the VS2008 xutility file
if (!_Pred(_Left, _Right))
with the message that it cannot convert parameter 1 from const V to const std::pair<_Ty1,_Ty2>
This seems to be caused by line 3795 of the file
if (_DEBUG_LT_PRED(_Pred, *_First2, *_First1))
where the first and second arguments seem to have been swapped
Compiling in Release Configuration gives the same error on line 3795, so it seems the Visual Studio implementation wants you to go through this code unless you tinker with whatever switch (if any) removes this '_DEBUG_LT_PRED' macro.
My question is:
Is this a bug in Visual Studio or is there a reason for this to be this way and I am making a mistake? I haven't done any C++ in over a decade and had to pick up last week to get some speed ups in some tight loops so need all the help I can get.
Thanks all
Nice,
I didn't think about the requirements of the algo. Makes sense it needs to check "less than" from both sides.
Not getting much joy getting this to compile though.
With my previous code of
template <class P,class K>
struct mapKey_set_cmp //: public std::binary_function<P,K,bool>
{
inline bool operator() (const P& x, const K& y) const {return x.first < y ;};
};
I was getting
error C2664: 'bool mapKey_set_cmp<P,K>::operator ()(const P &,const K &) const' :
cannot convert parameter 1 from 'const double' to 'const std::pair<_Ty1,_Ty2> &'
which makes sense as there is no operator() that can take a double as its 1st argument.
With the additional overloaded operator()
template <class P,class K>
struct mapKey_set_cmp //: public std::binary_function<P,K,bool>
{
inline bool operator() (const P& x, const K& y) const {return x.first < y ;};
inline bool operator() (const K& x, const P& y) const {return x < y.first ;};
};
I am now getting
error C2664: 'bool mapKey_set_cmp<P,K>::operator ()(const K &,const P &) const' :
cannot convert parameter 1 from 'const std::pair<_Ty1,_Ty2>' to 'const double &'
error C2664: 'bool mapKey_set_cmp<P,K>::operator ()(const K &,const P &) const' :
cannot convert parameter 1 from 'const std::pair<_Ty1,_Ty2>' to 'const double &'
error C2664: 'bool mapKey_set_cmp<P,K>::operator ()(const K &,const P &) const' :
cannot convert parameter 2 from 'const double' to 'const std::pair<_Ty1,_Ty2> &'
error C2664: 'bool mapKey_set_cmp<P,K>::operator ()(const K &,const P &) const' :
cannot convert parameter 2 from 'const double' to 'const std::pair<_Ty1,_Ty2> &'
Of note is that all the errors seem to reffer to the 2nd operator(), the one with the K 1st and P 2nd. And yes, none of the conversions mentioned should be possible on that operator. But why isn't the compiler trying the other operator? ie the one on which those conversions should be allowed. (BTW the errors are repeated because they each occur on two different lines in case you are wondering)
Another thing this could be is of course const incorrectness. It's been a while so I'll try to think that through.
Thanks for the help
Edit on 15 May 2013
I had to "get on with it" so circumvented this problem by puting my map Keys into a set so that I could call the includes algo on two sets (incurring the obvious performance penalty). I would still like to solve this properly though. Here is all the code neded to replicate the compiler error I am describing with Visual Studio 2008
template <class PAIR,class KEY>
struct mapKey_set_less : public std::binary_function<PAIR,KEY,bool>
{
inline bool operator() (const PAIR& x, const KEY& y) const {return x.first < y ;};
inline bool operator() (const KEY& x, const PAIR& y) const {return x < y.first ;};
};
int _tmain(int argc, _TCHAR* argv[])
{
map<string,double> theMap;
theMap["arse"] = 1;
set<string> theSet;
theSet.insert("arse");
typedef map<string,double>::iterator MI;
MI mi(theMap.begin()), miend(theMap.end());
typedef set<string>::iterator SI;
SI si(theSet.begin()), siend(theSet.end());
typedef mapKey_set_less< pair<string,double>,string> cmp;
if (includes(mi,miend,si,siend,cmp()))
{}
}
The compiler spits out
Error 1 error C2664: 'bool mapKey_set_less<PAIR,KEY>::operator ()(const KEY &,const PAIR &) const' : cannot convert parameter 1 from 'std::pair<_Ty1,_Ty2>' to 'const std::string &' c:\program files (x86)\microsoft visual studio 9.0\vc\include\xutility 346
Error 2 error C2664: 'bool mapKey_set_less<PAIR,KEY>::operator ()(const KEY &,const PAIR &) const' : cannot convert parameter 1 from 'std::pair<_Ty1,_Ty2>' to 'const std::string &' c:\program files (x86)\microsoft visual studio 9.0\vc\include\xutility 348
Error 3 error C2664: 'bool mapKey_set_less<PAIR,KEY>::operator ()(const KEY &,const PAIR &) const' : cannot convert parameter 2 from 'std::basic_string<_Elem,_Traits,_Ax>' to 'const std::pair<_Ty1,_Ty2> &' c:\program files (x86)\microsoft visual studio 9.0\vc\include\xutility 346
Error 4 error C2664: 'bool mapKey_set_less<PAIR,KEY>::operator ()(const KEY &,const PAIR &) const' : cannot convert parameter 2 from 'std::basic_string<_Elem,_Traits,_Ax>' to 'const std::pair<_Ty1,_Ty2> &' c:\program files (x86)\microsoft visual studio 9.0\vc\include\xutility 348
Looking at the 1st error alone it seems that it wants to use the operator()(KEY,PAIR) to pass in PAIR,KEY. Why is it ignoring the available operator()(PAIR,KEY)???
The other errors are all in the same vein, the compiler "appears" to ignore a perfectly good overloaded operator
Thanks all for the help
There is no requirement from the standard that objects from the first range will only be passed as the left hand argument of the comparison function, nor that objects in the second range will only be passed as the right hand argument. So, what Visual Studio is doing is perfectly valid, and often necessary (see below).
What you can do is write a single functor that handles both cases:
template <class K,class P>
struct set_mapKey_less : public std::binary_function<K,P,bool>
{
inline bool operator() (const K& x, const P& y) const {return x < y.first;};
inline bool operator() (const P& y, const K& x) const {return y.first < x; }
};
...
std::map<int,int> m;
std::set<int> s;
std::includes(m.begin(), m.end(), s.begin(), s.end(),
set_mapKey_less<int,std::pair<int const,int> >());
To understand why the check that VS is doing might be necessary, consider the following:
set X = { 1000, 3000, 5000, 7000, 9000 }
map Y = { (3000,'a') }
How are you going to test whether X includes Y if all you have is an less than operator that takes a pair value on the left, and an integer on the right?
Is (3000,'a').first < 1000? No.
Is (3000,'a').first < 3000? No.
Is (3000,'a').first < 5000? Yes.
At this point, we know that (3000,'a').first, if in the set, has to be 3000. But how do we test that it actually is 3000 with a comparator that can only take the pair on the left side? If we can reverse the arguments, we can do it:
Is 3000 < (3000,'a').first? No.
So now we know that 3000 is not less than (3000,'a').first, and (3000,'a').first is not less than 3000, therefore they must be equal.
Compilation error in VS2010:
c:\program files (x86)\microsoft visual studio 10.0\vc\include\algorithm(1840): error C2678: binary '=' : no operator found which takes a left-hand operand of type 'const triangle' (or there is no acceptable conversion)
h:\kingston_backup\ocv\ocv\delaunay.h(281): could be 'triangle &triangle::operator =(const triangle &)'
while trying to match the argument list '(const triangle, const triangle)'
c:\program files (x86)\microsoft visual studio 10.0\vc\include\algorithm(1853) : see reference to function template instantiation '_FwdIt std::_Remove_if,_Pr>(_FwdIt,_FwdIt,_Pr)' being compiled
with
[
_FwdIt=std::_Tree_unchecked_const_iterator,std::allocator,true>>>,
_Mytree=std::_Tree_val,std::allocator,true>>,
_Pr=triangleIsCompleted
]
h:\kingston_backup\ocv\ocv\delaunay.cpp(272) : see reference to function template instantiation '_FwdIt std::remove_if,triangleIsCompleted>(_FwdIt,_FwdIt,_Pr)' being compiled
with
[
_FwdIt=std::_Tree_const_iterator,std::allocator,true>>>,
_Mytree=std::_Tree_val,std::allocator,true>>,
_Pr=triangleIsCompleted
]
I think the problem is in passing the arguments to the remove_if() of the STL, as suggested by the compiler error. I have added the following comment to the line:
//**** ERROR LINE
class triangleIsCompleted
{
public:
triangleIsCompleted(cvIterator itVertex, triangleSet& output, const vertex SuperTriangle[3])
: m_itVertex(itVertex)
, m_Output(output)
, m_pSuperTriangle(SuperTriangle)
{}
bool operator()(const triangle& tri) const
{
bool b = tri.IsLeftOf(m_itVertex);
if (b)
{
triangleHasVertex thv(m_pSuperTriangle);
if (! thv(tri)) m_Output.insert(tri);
}
return b;
}
};
// ...
triangleSet workset;
workset.insert(triangle(vSuper));
for (itVertex = vertices.begin(); itVertex != vertices.end(); itVertex++)
{
tIterator itEnd = remove_if(workset.begin(), workset.end(), triangleIsCompleted(itVertex, output, vSuper)); //**** ERROR LINE
// ...
}
remove_if does not remove anything (in the sense of erasing). It copies values around, so that all remaining values end up at the beginning of the range (and the rest of the range is in a more or less unspecified state).
Since keys in an associative container are immutable, it is not possible to copy values from one place to another within a set, so remove_if can't work for it.
The standard library does not seem to contain remove_if for set, so you'd have to roll your own. It might look like this:
#include <set>
template <class Key, class Compare, class Alloc, class Func>
void erase_if(std::set<Key, Compare, Alloc>& set, Func f)
{
for (typename std::set<Key, Compare, Alloc>::iterator it = set.begin(); it != set.end(); ) {
if (f(*it)) {
set.erase(it++); //increment before passing to erase, because after the call it would be invalidated
}
else {
++it;
}
}
}