Reputation: 45
If I have a class with 2 std::map
properties, both with different comparators, then how can I write a function to return either of them?
E.g.:
class Test {
public:
std::map<int, int> &get_map(int id) {
if (id == 1)
return map_1;
else
return map_2;
}
private:
std::map<int, int, std::less<int>> map_1;
std::map<int, int, std::greater<int>> map_2;
};
Here the compiler will fail because map_2
is not std::map<int, int>
.
I also tried std::map<int, int, std::binary_function<int, int, bool>>
as the return type, but that doesn't work either.
Upvotes: 2
Views: 361
Reputation: 35706
Another option is to write your own comparator with parameter:
struct Cmp {
Cmp(bool is_less) : is_less(is_less)
{}
bool operator()(int lhs, int rhs) const {
if (is_less) {
return lhs < rhs;
} else {
return lhs > rhs;
}
}
private:
bool is_less;
};
Now you can use it in both of std::map
with different value of is_less
parameter:
class Test {
public:
Test() :
map_1(Cmp(true)),
map_2(Cmp(false))
{}
std::map<int, int, Cmp> &get_map(int id) {
if (id == 1)
return map_1;
else
return map_2;
}
private:
std::map<int, int, Cmp> map_1;
std::map<int, int, Cmp> map_2;
};
Upvotes: 1
Reputation: 217145
As alternative, you might erase comparer type, to have same map type:
class Test {
public:
std::map<int, int, bool (*)(int, int)> &get_map(int id) {
return (id == 1) ? map_1 : map_2;
}
private:
std::map<int, int, bool (*)(int, int)> map_1 = {+[](int lhs, int rhs) { return lhs < rhs; }};
std::map<int, int, bool (*)(int, int)> map_2 = {+[](int lhs, int rhs) { return lhs > rhs; }};
};
Upvotes: 2
Reputation: 238311
There is no way to write a function that can return either directly, because they have a different type (with no common base class). You can however have a function template:
template<class Comp>
std::map<int, int, Comp>& get_map();
Here, id
is redundant because the member is identified by the template argument.
Or you could wrap a pointer to either in a tagged union, and return that. For example:
std::variant<
std::map<int, int, std::less<int>>*,
std::map<int, int, std::greater<int>>*
>
get_map(int id);
Object oriented approach could be to not provide a getter at all, and only operate on the maps within the class.
Upvotes: 4
Reputation: 122228
Short answer: You cannot.
Templates are just templates. Different instantiations of templates are different types. If map
would be your type, then you could make different instantiations inherit from a common base and use them polymorphically. However, std::map
is not your type, so you cannot do that. You could return a std::variant
, but writing two getters is much easier.
Last but not least, note that if you return a non-const reference to a private member, then there is practiaclly no encapsulation. You could as well make the members public, which will also eliminate your current problem.
Upvotes: 2