In my code I often have functions doing the same thing on different iterable Qt Container types, for instance:
void removeX(QMap<qint64, QString> & map)
{
QMutableMapIterator<qint64, QString> it(map);
while (it.hasNext()) {
it.next();
if (it.value() == "X") it.remove();
}
}
void removeX(QList<QString> & list)
{
QMutableListIterator<QString> it(list);
while (it.hasNext()) {
it.next();
if (it.value() == "X") it.remove();
}
}
(and I know there is already a removeAll
function in QList. This is just a silly minimal example)
The actual code is more complex and hence this introduces a lot of code duplication. I would prefer to have something like:
template <typename T>
void removeX_(T & container)
{
typename T::mutable_iterator it(container);
while (it.hasNext()) {
it.next();
if (it.value() == "X") it.remove();
}
}
Of course, this doesn't compile, as there is simply no "::mutable_iterator" type definition within Qt. Could one construct one? I don't see a easy way to so. A function like "template<...> getMyMutableIterator" can't work in this case, as we are not allowed to return different types for an overloaded function.
But there is a plenty of new "template magic" from C++17 which I have not really understood yet. I could imagine that it could be a easy way to realize the above code. Has anyone a solution to reduce the code duplication here?
You can define a traits template, and partially specialise for the appropriate containers
template <typename Container> struct q_container_traits;
template <typename T> struct q_container_traits<QList<T>>
{
using mutable_iterator = QMutableListIterator<T>;
using const_iterator = QListIterator<T>;
};
template <typename Key, typename Value> struct q_container_traits<QMap<Key, Value>>
{
using mutable_iterator = QMutableMapIterator<Key, Value>;
using const_iterator = QMapIterator<Key, Value>;
};
// etc
You then use q_container_traits<T>
in your function.
template <typename T>
void removeX(T & container)
{
typename q_container_traits<T>::mutable_iterator it(container);
while (it.hasNext()) {
it.next();
if (it.value() == "X") it.remove();
}
}
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