为何std::plus无法调用std::vector的operator+运算符?
为什么std::accumulate默认无法调用全局的vector operator+?
问题现象
- GCC和MSVC编译不带自定义二元函数的
std::accumulate代码时均报错,GCC的错误信息为:invalid operands to binary expression ('typename std::remove_reference<vector<int> &>::type' (aka 'std::vector<int>') and 'std::vector<int>') - 但在lambda表达式里显式写
a + b时,两款编译器都能正常通过编译。
代码示例:
#include <vector> #include <algorithm> #include <iterator> #include <numeric> using namespace std; vector<int> operator+(const vector<int> &a, const vector<int> &b) { vector<int> c; transform(a.begin(), a.end(), b.begin(), back_inserter(c), plus()); return c; } int main() { vector<vector<int>> vv{{0, 1}, {2, 3}, {4, 5}}; // vector<int> s = accumulate(vv.begin() + 1, vv.end(), vv[0]); // 编译错误 vector<int> s = accumulate(vv.begin() + 1, vv.end(), vv[0], [](const auto &a, const auto &b) { return a + b; }); // 正常编译 return 0; }
原因分析
问题根源在std::accumulate默认使用的std::plus<>的查找规则:
- 默认调用
std::accumulate时,内部会用std::plus<>()执行累加。std::plus属于std命名空间,它查找operator+时,只会通过**参数依赖查找(ADL)**检查参数类型所在的命名空间——这里std::vector在std里,所以只会找std中的vector<int>加法运算符,而我们定义的operator+在全局命名空间,自然找不到。 - 而lambda里的
a + b是在全局上下文查找的,能直接找到我们在全局定义的operator+,所以编译没问题。
解决方案
有两种靠谱的解决方式:
- 显式传入自定义二元函数:就像示例里的lambda写法,或者也可以直接写个简单的函数对象:
struct VectorAdd { vector<int> operator()(const vector<int>& a, const vector<int>& b) const { return a + b; } }; // 调用时 vector<int> s = accumulate(vv.begin() + 1, vv.end(), vv[0], VectorAdd()); - 改用普通函数实现向量加法:放弃重载
operator+,直接写一个全局函数,然后在accumulate里调用:vector<int> add_vectors(const vector<int>& a, const vector<int>& b) { vector<int> c; transform(a.begin(), a.end(), b.begin(), back_inserter(c), plus()); return c; } // 调用时 vector<int> s = accumulate(vv.begin() + 1, vv.end(), vv[0], add_vectors);
注意:不要把自定义的operator+放进std命名空间,这属于修改标准库命名空间,是C++标准未定义的行为,可能引发各种未知问题。
内容的提问来源于stack exchange,提问作者chaosink
相关产品推荐
相关产品推荐

