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.
If I create an abstract parent class and declare a single map member, is there any way to dynamically assign the comparator for this member in the derived class constructors? That way the functionality can obviously all reside in the parent class.
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.
来源:https://stackoverflow.com/questions/28955044/c-dynamically-assign-stdmap-comparator