Say we have something like this:
template<typename T>
class SparseMatrix {
// Where the first (K,V) is (row_idx, columns) and the second is (col_idx, numeric type)
using Entries = std::unordered_map<unsigned long, std::unordered_map<unsigned long, T>>;
Entries data;
//...
};
For sparse matrices, we want to ignore rows that are mutually empty, so (I think) we could implement addition with something like this:
template<typename K, typename V>
std::unordered_map<K, V> operator+(
const std::unordered_map<K,V>& left,
const std::unordered_map<K,V>& right
) {
std::unordered_map<K, V> result(left);
for (auto& p: result) {
if (right.count(p.first) > 0) {
result[p.first] += right[p.first]; // += def'n not shown...
}
}
for (auto& p: right) {
if (result.count(p.first) == 0) {
result[p.first] = p.second;
}
}
return result;
}
// ...
SparseMatrix::SparseMatrix operator+(const SparseMatrix& right)
{
// checks and whatnot...
// Uses the custom + operator: the "sum" of two unordered_maps!!!
return this->data + right.data;
}
I think this template is convenient because it handles the outer and inner operations simultaneously; however, because this should happen in a header file, if possible I'd like to make the unordered_map
operator definition private to SparseMatrix
, as it only has meaning there. I do not want std::unordered_map<K,V> operator+
to be visibly defined for anyone who #includes this implementation.
What idiomatic options do I have, other than globally declaring the operator definition(s) for the STL container?
If anything else I've drafted above is not idiomatic C++, I'd really appreciate any feedback.
Naively, I tried to paste that implementation in SparseMatrix 's private section, and ran into an error which states I'm providing too many parameters to the function. Removing the left
parameter and replacing it with the private member, data, then results in the + operation not being defined for MatrixVals . My assumption for what's going on here is possibly that I've introduced a circular dependency. Is that the case?
I did not find any other SO post describing how to limit the scope of an operator overload in this way.
Operators for classes you don't own is generally a bad idea
But we can still do it. Making it static
or friend
inside the class scope doesn't seem to work, so the best way seems to be to put it into a private namespace.
namespace SparseMatrixImpl {
template<typename K, typename V>
std::unordered_map<K, V> operator+(
std::unordered_map<K,V>& left,
std::unordered_map<K,V>& right
) {
...
}
}
and then pull that function into the overload set when you need it
SparseMatrix::SparseMatrix operator+(const SparseMatrix& right)
{
// checks and whatnot...
// Uses the custom + operator: the "sum" of two unordered_maps!!!
using SparseMatrixImpl::operator+;
return this->data + right.data;
}
http://coliru.stacked-crooked.com/a/5f65464c73b727e0
The better idea
is to simply call it something else, that is globally useful, such as accumulate
.
template<typename K, typename V>
std::unordered_map<K, V> accumulate(
std::unordered_map<K,V>& left,
std::unordered_map<K,V>& right
) {
...
}
http://coliru.stacked-crooked.com/a/c4b22e87354ccedf