问题
As the question says, I need to use std::map in such way that.
std::map<std::pair<int, int>, int*> m;
int* a_ptr = new int;
*a_ptr = 15;
m[std::make_pair(1, 2)] = a_ptr;
std::cout << *m[std::make_pair(2, 1)] << std::endl; //should output 15
Now, in my actual implementation all the keys and values are actually pointers. How should I approach this problem?
Two ideas come to my mind.
One is I should write a function that every time I am using
m[]
to access or to write into map, I should alsom.find()
check the other pair combination and act according to that.Other is using std::unordered_map with a custom hasher that somehow makes no difference when
pair
's elements positions are switched. (I have no idea how to do this, if I multiply or add the two pointers the result won't be equal. Need some help if this is the way to go.)
If you can think a better method I will be glad to hear it, otherwise I have stated what I need help with in the second clause. (which I think is more efficient, first one does not look good)
Thanks.
回答1:
Could you simply ensure the pairs are always in the same order? Use a helper function, like:
std::pair<int,int> my_make_pair(int a, int b)
{
if ( a < b ) return std::pair<int,int>(a,b);
else return std::pair<int,int>(b,a);
}
and always use it to access the map:
m[my_make_pair(1,2)] = a_ptr;
std::cout << m[my_make_pair(2, 1)] << std::endl;
回答2:
Just use a custom comparator
[](std::pair<int, int> const& lhs, std::pair<int, int> const& rhs) {
int lhs_min = std::min(lhs.first, lhs.second);
int lhs_max = std::max(lhs.first, lhs.second);
int rhs_min = std::min(rhs.first, rhs.second);
int rhs_max = std::max(rhs.first, rhs.second);
return lhs_min < rhs_min || (!(rhs_min < lhs_min) && lhs_max < rhs_max)
}
How does this work?
The first few lines deterministically order the 2 elements of a pair; that is, you can supply them in either order and lhs_min
& lhs_max
will be the same. We then use a standard equivalence technique for the result. All integer copies will be optimised out by the compiler and min
/max
will be inlined.
Note that I used C++11's lambdas for convenience of typing and have since discovered that there is no nice way of using them as the comparator for a std::map
, so you would have to write a functor proper.
回答3:
template<typename T, typename PairCmp = std::less<std::pair<T,T>> >
struct symmetric_pair_sort {
bool operator()( std::pair<T,T> const& left, std::pair<T,T> const& right ) const {
if (left.second<left.first) {
return (*this)(std::make_pair( left.second, left.first ), right );
}
if (right.second<right.first) {
return (*this)(left, std::make_pair( right.second, right.first ) );
}
return PairCmp()(left, right);
}
};
// or, the far bulkier yet more efficient:
template<typename T, typename PairCmp = std::less<std::pair<T&, T&>> >
struct symmetric_pair_sort {
template<bool left_reversed, bool right_reversed>
bool Helper( std::pair<T,T> const& left, std::pair<T,T> const& right ) const {
std::pair<T&, T&> left_ordered( left_reversed?left.first:left.second, left_reversed?left.second:left.first );
std::pair<T&, T&> right_ordered( right_reversed?right.first:right.second, right_reversed?right.second:right.first );
return PairCmp()( left_ordered, right_ordered );
}
bool operator()( std::pair<T,T> const& left, std::pair<T,T> const& right ) const {
if (left.second<left.first) {
if (right.second<right.first) {
return Helper<true, true>(left, right);
} else {
return Helper<true, false>(left, right);
}
} else {
if (right.second<right.first) {
return Helper<false, true>(left, right);
} else {
return Helper<false, false>(left, right);
}
}
};
std::map<std::pair<int, int>, int*, symmetric_pair_sort<int> > m;
回答4:
An alternative solution is to use std::set<int>
instead of std::pair<int,int>
. Sets store their data ordered, hence there is no need to order your pair, so precisely fulfill your requirement.
On the other hand, the other answers to use a compare wrapper around pair that explicitly orders the pairs might be more practical.
来源:https://stackoverflow.com/questions/15420086/stdmap-with-stdpair-keys-where-pair-elements-has-no-order-importance