So I have two classes containing std::map members with effectively identical functionality except that the ordering of one map is std::less and the other std::greater.
You can't change the comparator after the fact. But you can use the same comparator class and get either "greater" or "less" at the time of construction. You just need a stateful comparator:
struct my_compare {
enum compare_type { less, greater };
explicit my_compare(compare_type t) : m_type(t) {}
template<class T, class U>
bool operator()(const T& t, const U& u) const {
if(m_type == less) { return t < u; }
else { return t > u; }
}
compare_type m_type;
};
Then you can do
std::map<int, int, my_compare> less_map((my_compare(my_compare::less)));
std::map<int, int, my_compare> greater_map((my_compare(my_compare::greater)));
The extra pair of parentheses is because it would otherwise be the most vexing parse , even though a function parameter declaration cannot have a qualified name. In C++11, list-initialization (my_compare{mycompare::less}
) can be used instead.
For your specific design, an implementation might look like
class A {
protected:
explicit A(my_compare::compare_type ct) : my_map(my_compare(ct)) {}
std::map<int, int, my_compare> my_map;
};
class B_less : public A{
public:
B_less() : A(my_compare::less) {}
};
No. The comparison function is used to generate the actual data structure -- changing the comparison function would require rebuilding the structure from scratch.
That said, if all you want to do is iterate the structure in reverse order, map
is a reversible container, so you can just loop over the structure normally using the reverse iterators.
You can do what you want to do by creating a custom functor class that uses less or greater depending on some state. Here's an example:
#include <iostream>
#include <string>
#include <map>
struct MyCompare
{
MyCompare(bool useLess) : useLess_(useLess) {}
bool operator()(int lhs, int rhs)
{
if ( useLess_ )
{
return (lhs < rhs);
}
else
{
return (lhs > rhs);
}
}
bool useLess_;
};
int main(int argc, char** argv)
{
std::map<int, std::string, MyCompare> myMap1(MyCompare(true));
std::map<int, std::string, MyCompare> myMap2(MyCompare(false));
myMap1[1] = "abcd";
myMap1[2] = "lmnop";
myMap1[3] = "xyz";
myMap2[1] = "abcd";
myMap2[2] = "lmnop";
myMap2[3] = "xyz";
std::cout << "Map 1: " << std::endl; for ( auto const& v : myMap1 )
{
std::cout << "Key: " << v.first << ", Value: " << v.second << std::endl;
}
std::cout << "Map 2: " << std::endl;
for ( auto const& v : myMap2 )
{
std::cout << "Key: " << v.first << ", Value: " << v.second << std::endl;
}
return 0;
}
Output:
Map 1: Key: 1, Value: abcd Key: 2, Value: lmnop Key: 3, Value: xyz Map 2: Key: 3, Value: xyz Key: 2, Value: lmnop Key: 1, Value: abcd
In your case, you can pass a flag from the child class to the parent class indicating what value to use to create the compare functor.