重载二维vector的operator+时使用std::plus<T>编译报错求助
我在Codewars练习编程时遇到一道矩阵加法题,要求编写函数接收两个N×N整数方阵并返回它们的和。
最初我实现了一维vector的operator+重载,把它当成一维矩阵来处理,代码能正常运行。后来想扩展成二维vector的operator+重载,希望直接用sum = a + b完成矩阵加法,但写的代码编译失败。
我的二维vector重载operator+代码如下:
template <typename T> std::vector<std::vector<T>> operator+(const std::vector<std::vector<T>>& a, const std::vector<std::vector<T>>& b) { /* * Add 2-dimensional vectors * */ assert (a.size() == b.size()); std::vector<std::vector<T>> sum; // Allocate memory for 2nd dimension size_t dim2size = a.size(); sum.reserve(dim2size); // Allocate memory for 1st dimension size_t dim1size = a[0].size(); for (size_t i=0; i<dim2size; i++) sum[i].reserve(dim1size); std::transform( a.begin(), a.end(), b.begin(), std::back_inserter(sum), std::plus<std::vector<T>>() ); return sum; }
编译报错信息:
/usr/include/c++/14/bits/stl_function.h:190:20: error: no match for
‘operator+’ (operand types are ‘const std::vector’ and ‘const
std::vector’)
朋友建议用lambda表达式[](const std::vector<int>&a, const std::vector<int>& b) {return a+b;}替代std::plus<std::vector<T>>(),但我想知道用std::plus<std::vector<T>>()时出问题的原因是什么?
编译失败的核心问题有两个,跟std::plus的调用逻辑和你写的重载函数的可见性有关:
1. 一维vector的operator+签名不匹配
std::plus<std::vector<T>>()的内部实现是直接调用lhs + rhs,这里的lhs和rhs都是const引用类型(const std::vector<T>&)。如果你之前写的一维vector的operator+重载没有用const修饰参数(比如签名是std::vector<T> operator+(std::vector<T>& a, std::vector<T>& b)),编译器就找不到能处理const引用的operator+,直接报“no match for operator+”错误。
2. 参数依赖查找(ADL)的范围限制
std::plus是在std命名空间里的模板,当它调用lhs + rhs时,编译器会通过ADL规则,只在std命名空间(因为参数std::vector属于std)和当前函数所在的命名空间里查找operator+。但你写的operator+是全局命名空间的,不在ADL的查找范围内,所以编译器找不到你的重载版本。
而朋友建议的lambda表达式不一样:lambda是在你的重载函数内部定义的,全局命名空间的operator+在这个上下文里是可见的,所以lambda里调用a+b时,能正常找到你写的一维vector的operator+重载。
另外提一句,你的代码里还有个潜在bug:sum.reserve(dim2size)只是预留了内存,但sum的size还是0,此时访问sum[i]会越界,这部分代码应该删掉,std::transform配合std::back_inserter会自动帮你添加元素,不需要手动预分配内层vector的空间。
内容的提问来源于stack exchange,提问作者Asmoox

