我正在尝试重载std :: vector的+和+ =运算符,而我要做的是
namespace std {
template<class T>
vector<T> operator+(vector<T> x, vector<T> y) {
vector<T> result;
result.reserve(x.size());
for (size_t i = 0; i < x.size(); i++)
result[i] = x[i] + y[i];
return result;
}
}
但是我认为这是不好的做法,因为clang-tidy警告我“ std名称空间的修改可能导致未定义的行为”。在STL类的重载运算符上还有其他更好的做法吗?
答案 0 :(得分:6)
最佳做法是不这样做。
但是,如果您确实想要,您仍然可以:只是不要将其放在命名空间std
中。
不要按值接受参数,除非您故意这样做以充分利用移动语义(不是)。
答案 1 :(得分:4)
我建议:
namespace
中。示例:
namespace MyApp
{
template <typename T>
std::vector add(std::vector<T> const& lhs, std::vector<T> const& rhs) { ... }
template <typename T>
std::vector& append(std::vector<T>& lhs, std::vector<T> const& rhs) { ... }
}
答案 2 :(得分:4)
在std
中插入函数会使您的程序格式错误,无需进行诊断。
在某些有限的情况下,您可以在std
中插入专业化名称,但这不能满足您的要求。
因此您不能将vec + vec
插入std
。
将运算符放置在其他名称空间中是合法的,但建议不要这样做。当无法通过ADL / Koenig查找找到操作员时,它们将无法正常工作。看起来合理的代码(例如std::accumulate( vec_of_vec.begin(), vec_of_vec.end(), std::vector<int>{} )
无法编译等问题。
简而言之,vector
不是您的类型。不要这样做。
您可以在其他地方创建辅助函数,例如util::elementwise_add( vec, vec )
。
std
没有实现+
,因为在合理的情况下,隐含和元素操作都是如此。 valarray
确实实现了元素操作;可能您想要的是std::valarray<int>
而不是std::vector<int>
。
如果所有操作失败,则可以在自己的名称空间中编写命名操作符vec +by_elem+ vec
或从std::vector
继承,使用该类型,并为类型重载+
。 (从std::vector
继承是非常安全的;只要没有人玩堆分配的指向std::vector
或类似对象的原始指针即可
答案 3 :(得分:2)
无论您是将加法实现为operator+(...)
还是将功能实现为add(...)
,都最好采用以下方式:
template<class T>
std::vector<T> operator+(std::vector<T> x, const std::vector<T>& y) {
assert(x.size() == y.size());
for (std::size_t i = 0; i < x.size(); ++i)
x[i] += y[i];
return x;
}
通过按值(而不是const-ref)获取第一个向量,您将强制编译器自动为您创建一个副本以保存结果。
读完this comment后添加。
由于+
从左到右的关联性,像a + b + c
这样的表达式被解析为(a + b) + c
。因此,如果按值采用operator+(... x, ... y)
中的第一个(而不是第二个)参数,则可以将a + b
返回的 prvalue 移到x
中。否则,将制作不必要的副本。
答案 4 :(得分:0)
您应该创建自己的从std :: vector继承的vector类,并定义新的运算符
#include <iostream>
#include <vector>
template<class T>
class MyVec : public std::vector<T>
{
public:
MyVec& operator+=(const T& add)
{
reserve(1);
push_back(add);
return *this;
}
};
int main()
{
MyVec<int> vec;
vec += 5;
vec += 10;
for (auto& e : vec)
{
std::cout << e << "\t";
}
std::cin.get();
}
编辑:对不起,我不知道此解决方案会导致不确定的行为。然后,我建议上面的帖子中所示的类似解决方案。但是,为什么需要加号运算符? push_back是否足够好?您可以实现参考返回值以继续添加。因此,您可以执行以下操作:
vec + 20 + 30;
添加两个元素(20和30)。这是更少的代码,但可读性更高?