I am trying to use the std::tie
to implement the operator<
in order to create a map of structs that contain a set. The same code without templates seem that it works. I am getting this message code from my compiler:
/usr/include/c++/4.8/bits/stl_algobase.h:888: error: no match for
operator<
(operand types areconst SiPa<int, int>
andconst SiPa<int, int>
)if (*__first1 < *__first2) ^
Everything compiles if I comment the myMap.insert({akey, true});
line.
Any hints?
template<class I = int, class S = int>
struct SiPa
{
I i;
S s;
};
template<class I = int, class S = int>
struct SiPaComparator
{
bool operator() (const SiPa<I, S>& first, const SiPa<I, S>& second) const
{
return std::tie(first.i, first.s) < std::tie(second.i, second.s);
}
};
template<class I = int, class S = int>
struct AKey
{
typedef std::set< SiPa<I, S>, SiPaComparator<I,S> > SetType;
SetType keySet;
I keyI;
};
template<class I = int, class S = int>
struct AKeyComparator
{
bool operator() (const AKey<I, S>& first, const AKey<I, S>& second) const
{
return std::tie(first.keySet, first.keyI) < std::tie(second.keySet, second.keyI);
}
};
int main()
{
AKey<int,int> akey;
std::map<AKey<int,int>, bool, AKeyComparator<int,int>> myMap;
myMap.insert({akey, true});
}
You need add operator< for struct SiPa, std::map require it
template<class I = int, class S = int>
struct SiPa {
I i;
S s;
bool operator<(const SiPa<I, S> &ref) {
return i < ref.i && s < ref.s;
}
};
In general, comparators on map
s and set
s are stateful . When comparing two different set
s or map
s, there is no obvious way to pick which one to use.
So when comparing different set
s and map
s via <
, you get std::lexographical_compare
with no Compare
argument, which uses <
. (Note this sucks for set
s of pointers to objects not from the same array)
struct order_by_tie {
template<class Lhs, class Rhs,
class=std::enable_if_t<
std::is_base_of<order_by_tie, Lhs>::value
&& std::is_base_of<order_by_tie, Rhs>::value
>
>
friend bool operator<(Lhs const& lhs, Rhs const& rhs) {
return as_tie(lhs) < as_tie(rhs);
}
};
order_by_tie
is intended to be inherited from. It uses ADL (argument dependent lookup) to enable <
on its descendent classes, implemented by calling the free function as_tie
on each side then doing a <
.
We use it as follows:
template<class I = int, class S = int>
struct SiPa:order_by_tie
{
I i;
S s;
friend auto as_tie( SiPa const& self ) {
return std::tie(self.i, self.s);
}
};
template<class I = int, class S = int>
struct AKey:order_by_tie
{
typedef std::set< SiPa<I, S>, SiPaComparator<I,S> > SetType;
SetType keySet;
I keyI;
friend auto as_tie( AKey const& self ) {
return std::tie(self.keySet, self.keyI);
}
};
then
std::map<AKey<int,int>, bool> myMap;
works.
as_tie
uses C++14, because the alternative is annoying. You can add a -> decltype(std::tie( blah, blah ))
for C++11 (repeating yourself).
According to http://www.cplusplus.com/reference/set/set/operators/
The other operations also use the operators == and < internally to compare the elements, behaving as if the following equivalent operations were performed:
Notice that none of these operations take into consideration the internal comparison object of neither container .
So the comparaison of std::set<SiPa<I, S>, SiPaComparator<I,S>>
is done with
operator < (const SiPa<I, S>&, const SiPa<I, S>&)
and not with
SiPaComparator<I, S>{}
The workaround is to define that operator <
.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.