I have a here a bidirectional map. I make it form 0. I defined member functions like insert
count
size
and others and of course a function at
which returns a reference to the mapped value of the element identified with the given key. Until type A is not the same with type B everything works fine, but when type A is the same with type B i get an error that i try to overload this function at
, which is correct :( But my mind can`t help me with a method to solve this error. Maybe you can give me an example or tell me what i can do in this case :)
template <class A,class B>
class BidirectionalMap
{
public:
void insert(A a,B b)
{
m1.insert(std::pair<A,B> (a,b));
m2.insert(std::pair<B,A> (b,a));
}
BidirectionalMap& operator =(BidirectionalMap &a)
{
m1=a.m1;
m2=a.m2;
return *this;
}
A& at(const A& a)
{
if(m1.find(a)!=m1.end()) return m1.at(a);
else return m2.at(a);
}
const B& at(const A& b) const
{
return m1.at(b);
}
const A& at(const B& a) const
{
return m2.at(a);
}
int size() const
{
return m1.size();
}
int count(const A& a) const
{
return m1.count(a);
}
int count(const B& b) const
{
return m2.count(b);
}
B& operator[](const A& a)
{
return m1[a];
}
A& operator[](const B& b)
{
return m2[b];
}
private:
std::map<A,B> m1;
std::map<B,A> m2;
};
And what if i cannot modify this sequence in main()?
BidirectionalMap<int, int> f;
f.insert(3, 18);
f.insert(8, 2);
f.insert(7, 5);
f.insert(9, 1);
const BidirectionalMap<int, int> cf = f;
if( f.at(5) == 7 &&
f.count(12) == 0 &&
f.at(8) == 2)
{
yourMark = cf[18] + cf[9];
}
Implement at
in a CRTP base class.
template<class D, class A, class B>
struct crtp_at {
D* self() { return static_cast<D*>(this); }
D const* self() const { return static_cast<D const*>(this); }
const B& at(const A& b) const {
return self()->m1.at(b);
}
const A& at(const B& a) const {
return self()->m2.at(a);
}
B& at(const A& b) {
return self()->m1.at(b);
}
A& at(const B& a) {
return self()->m2.at(a);
}
};
template<class D, class A>
struct crtp_at<D,A,A> {
D* self() { return static_cast<D*>(this); }
D const* self() const { return static_cast<D const*>(this); }
A& at(const A& a) {
if(self()->m1.find(a)!=self()->m1.end()) return self()->m1.at(a);
else return self()->m2.at(a);
}
A const& at(const A& a) const {
if(self()->m1.find(a)!=self()->m1.end()) return self()->m1.at(a);
else return self()->m2.at(a);
}
};
Then your class uses the above like:
template <class A,class B>
class BidirectionalMap:public crtp_at< BiDirectionalMap<A,B>, A, B >
{
// rest of your code
};
however, I would advise actually blocking at
in that case, and any other method where it is not clear which way you are going.
You should have methods that clearly go one way or the other in your code for cases like short <-> double
anyhow.
Here is a solution which is close to @Yakk's one but is based on my old solution to the similar problem:
#include <type_traits>
template <class A, class B>
class BidirectionalMap;
template <class A, class B, bool = std::is_same<A, B>::value>
class BaseMap
{
public:
BidirectionalMap<A, B>* self()
{
return static_cast<BidirectionalMap<A, B>*>(this);
}
const BidirectionalMap<A, B>* self() const
{
return static_cast<const BidirectionalMap<A, B>*>(this);
}
const A& at(const B& a)
{
return self()->m2.at(a);
}
const A& at(const B& a) const
{
return self()->m2.at(a);
}
// ...
};
template <class A, class B>
struct BaseMap<A, B, true> {};
template <class A, class B>
class BidirectionalMap : public BaseMap<A, B>
{
public:
friend struct BaseMap<A, B>;
const B& at(const A& b)
{
return m1.at(b);
}
const B& at(const A& b) const
{
return m1.at(b);
}
// ...
private:
std::map<A, B> m1;
std::map<B, A> m2;
};
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With