提问人:Ders 提问时间:8/22/2023 最后编辑:Ders 更新时间:8/22/2023 访问量:63
如何私有地实现 STL 容器的运算符?
How do I privately implement an operator for an STL container?
问:
假设我们有这样的东西:
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;
//...
};
对于稀疏矩阵,我们想忽略互为空的行,所以(我认为)我们可以使用如下方式实现加法:
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;
}
我认为这个模板很方便,因为它同时处理外部和内部操作;但是,由于这应该发生在头文件中,因此如果可能的话,我想将运算符定义私有化,因为它仅在那里有意义。我不想为任何 #includes 此实现的人进行明显的定义。unordered_map
SparseMatrix
std::unordered_map<K,V> operator+
除了全局声明 STL 容器的运算符定义之外,我还有什么惯用选项?
如果我上面起草的其他内容不是惯用的C++,我将不胜感激任何反馈。
天真地,我试图将该实现粘贴到 SparseMatrix 的私有部分,并遇到了一个错误,指出我为函数提供了太多参数。删除参数并将其替换为私有成员 data,则会导致未为 MatrixVals 定义 + 操作。我对这里发生的事情的假设可能是我引入了循环依赖关系。是这样吗?left
我没有找到任何其他 SO 帖子来描述如何以这种方式限制运算符重载的范围。
答:
对于您不拥有的类,运算符通常不是一个好主意
但我们仍然可以做到。在类范围内制作它或在类范围内似乎不起作用,因此最好的方法似乎是将其放入私有命名空间中。static
friend
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
) {
...
}
}
然后在需要时将该函数拉入过载集
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
更好的主意
就是简单地称它为其他东西,它是全局有用的,例如 .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
此外,您在代码中还有各种其他错误和坏主意。也就是说,您正在尝试在“const”“right”上使用“operator[]”。
评论
std::accumulate
),其中运算符可以处理任意嵌套。请注意,这意味着我只做一次哈希查找。代码对每个键进行 2-3 次哈希查找。accumulate
find
评论
operator+(unordered_map, unordered_map)
static
friend