繁体   English   中英

向量的重载运算符+:命名空间标准

[英]Overload operator + for vector: namespace std

我正在尝试重载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类的重载运算符上还有其他更好的做法吗?

最佳做法是不这样做。

但是,如果您确实想要,您仍然可以:只是不要将其放在命名空间std

并且不要按值接受您的论据,除非您故意这样做是为了充分利用移动语义(不是)。

我建议:

  1. 不要使操作员超负荷。 而是创建常规函数。
  2. 将函数放在特定于您的应用程序的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) { ... }
}

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的原始指针或类似的指针)

无论您将加法实现为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),您将强制编译器自动为您创建一个副本以保存结果。

看完之后除了 这个评论

由于+的从左到右的关联性,像a + b + c的表达式被解析为(a + b) + c 因此,如果operator+(... x, ... y)的第一个(而不是第二个)参数是取值的,则a + b返回的prvalue可以移到x 否则,将制作不必要的副本。

您可能应该创建自己的从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)。 这是更少的代码,但更具可读性吗?

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM