C++ 在全局范围内,在std容器上重载运算符是一种糟糕的方式吗?

C++ 在全局范围内,在std容器上重载运算符是一种糟糕的方式吗?,c++,operator-overloading,argument-dependent-lookup,C++,Operator Overloading,Argument Dependent Lookup,我遇到了这个问题: // A.h #include <vector> typedef std::vector<unsigned char> Buffer; Buffer &operator+=(Buffer &a, Buffer const &b); 所描述的问题是a+=b;编译失败,因为Bar::operator+=Qux&,Qux const&隐藏::operator+=;ADL没有找到::operator+,因为ADL只搜索名称空间std;

我遇到了这个问题:

// A.h
#include <vector>
typedef std::vector<unsigned char> Buffer;
Buffer &operator+=(Buffer &a, Buffer const &b);
所描述的问题是a+=b;编译失败,因为Bar::operator+=Qux&,Qux const&隐藏::operator+=;ADL没有找到::operator+,因为ADL只搜索名称空间std;在这种情况下

这是令人讨厌的,因为问题只出现在包含B.h的情况下——但B.h显然与缓冲区无关。根据我是否包含另一个标头,代码不应该中断

实际上,我只是在更改编译器时才发现这一点,我使用的前一个编译器没有正确地查找名称,并接受了代码

我的问题是:由于这个问题,A.h中的过载是一个坏主意吗


我现在通过让B.h使用::operator+=,来解决这个问题;在名称空间栏中,但这似乎很有问题,有更好的选择吗?

我能想到的最简单、最安全、最可重用的方法是让+=参数中的一个在运算符的名称空间中具有某种类型:

template <typename T>
struct ArgumentRef
{
    ArgumentRef(T& t) : t_(t) { }
    operator T&() { return t_; }
    operator const T&() const { return t_; }
    T& t_;
};

typedef std::vector<unsigned char> Buffer;
Buffer &operator+=(ArgumentRef<Buffer> a, Buffer const &b) { }

< P>,继承——尽管C++中的非虚拟析构函数在向量中有争议,但通常是很好的,尤其是如果没有在API中公开缓冲区,以便在更广泛的用途上使用,而不使用代码中动态分配的实例,也设计了拥有和处理基类的方法。

< P>最简单、最安全,我能想到的最可重用的方法是让+=参数中的一个属于运算符命名空间中的类型:

template <typename T>
struct ArgumentRef
{
    ArgumentRef(T& t) : t_(t) { }
    operator T&() { return t_; }
    operator const T&() const { return t_; }
    T& t_;
};

typedef std::vector<unsigned char> Buffer;
Buffer &operator+=(ArgumentRef<Buffer> a, Buffer const &b) { }

,继承——虽然在C++循环中由于向量中的非虚析构函数而引起争议,但通常是很好的,特别是如果没有在API中公开缓冲区以供更广泛使用,并且在设计用来拥有和处理基类的代码中不使用动态分配的实例。

尽管我不确定在这种情况下运算符重载是否是一种糟糕的风格, 这可能是一个有争议的问题,你知道, 这似乎是“功能范围”的问题,而不是“操作员”的问题。 即使将“运算符+=”更改为“添加”, 你可能会得到同样的结果


这与本例中的运算符重载是否为不良样式无关。

尽管我不确定本例中的运算符重载是否为不良样式, 这可能是一个有争议的问题,你知道, 这似乎是“功能范围”的问题,而不是“操作员”的问题。 即使将“运算符+=”更改为“添加”, 你可能会得到同样的结果


在这种情况下,运算符重载是否属于不良样式与此问题无关。

如果使用::operator+=;添加,会发生什么;我想Kerrek的意思是如果使用::operator+=;添加;到foo?你的意思是将它添加到每个使用它的函数中?似乎比在B.h中做一次还要麻烦:如果您要为std名称空间中定义的任何类型重载任何运算符,我建议您在std名称空间中这样做。这在ADL中非常有效。@RSahu遗憾的是,要添加到std中需要UB。请参见[namespace.std]1如果使用::operator+=;添加会怎么样;我想Kerrek的意思是如果使用::operator+=;添加;到foo?你的意思是将它添加到每个使用它的函数中?似乎比在B.h中做一次还要麻烦:如果您要为std名称空间中定义的任何类型重载任何运算符,我建议您在std名称空间中这样做。这在ADL中非常有效。@RSahu遗憾的是,将UB添加到std中是很困难的。请参见[namespace.std]1这是非常正确的;所以我也可以通过调用我的函数my_buffer_append来解决这个问题,它比操作符+=,发生冲突的可能性更小;因此,我也可以通过调用函数my_buffer_append来解决这个问题,这比操作符+=,发生冲突的可能性更小。
template <typename T>
struct ArgumentRef
{
    ArgumentRef(T& t) : t_(t) { }
    operator T&() { return t_; }
    operator const T&() const { return t_; }
    T& t_;
};

typedef std::vector<unsigned char> Buffer;
Buffer &operator+=(ArgumentRef<Buffer> a, Buffer const &b) { }