实现是不是应该防止逗号重载?
Posted
技术标签:
【中文标题】实现是不是应该防止逗号重载?【英文标题】:Should the implementation guard itself against comma overloading?实现是否应该防止逗号重载? 【发布时间】:2012-02-01 22:32:16 【问题描述】:例如uninitialized_copy
在标准中定义为:
效果:
for (; first != last; ++result, ++first) ::new (static_cast<void*>(&*result)) typename iterator_traits<ForwardIterator>::value_type(*first);
如果从字面上理解,这是调用operator ,(ForwardIterator, InputIterator)
的要求。事实上,这段代码打印了十次Hello world!
:
#include <memory>
#include <iterator>
#include <iostream>
using namespace std;
namespace N
struct X : iterator<forward_iterator_tag, int>
pointer _p;
X(pointer p) : _p(p)
X& operator++() ++_p; return *this;
X operator++(int) X r(*this); ++_p; return r;
reference operator*() const return *_p;
pointer operator->() const return _p;
;
bool operator==(X a, X b) return a._p == b._p;
bool operator!=(X a, X b) return !(a == b);
void operator,(X a, X b) cout << "Hello world!\n";
int a[10], b[10];
int main()
using N::X;
uninitialized_copy(X(a), X(a+10), X(b));
但是,对于大多数其他算法,该标准以散文形式给出了描述。例如。对于copy
,不需要调用运算符,
。但是如果我改变了
uninitialized_copy(X(a), X(a+10), X(b));
在上面的代码中
copy(X(a), X(a+10), X(b));
那么Hello world!
仍然打印了十次。上述结果在 VS2005 和 GCC 4.3.4 中都可以观察到。但是,如果我写
mismatch(X(a), X(a+10), X(b));
相反,VS2005 打印 Hello world!
十次,但 GCC 没有。
不幸的是,我找不到标准在哪里禁止迭代器类型的 operator,
重载。相反,它禁止实现如上述 [global.functions] 进行调用:
除非另有规定,标准库中的全局和非成员函数不得使用通过参数相关名称查找 (3.4.2) 找到的另一个命名空间中的函数。
那么四方中谁错了:MSVC、GCC、ISO 还是我? (选择一项)
【问题讨论】:
我认为Visual C++、gcc和ISO都错了:Visual C++和gcc不应该使用逗号操作符,规范(ISO)也不应该在其示例代码中使用逗号。我可能是错的;这只是我对此事的第一个想法。 (请考虑在 Microsoft Connect 上打开一个 Visual C++ 错误;至少值得引起他们的注意。) 考虑到即使像Size
这样的东西也是一个模板类型,我会转过头来说标准想要精确它所说的,如果您看到提供自定义逗号运算符的理由,然后您被邀请这样做,您将获得指定的行为。
@JamesMcNellis KerrekSB:谢谢。我希望有人能找到一个据说是未定义行为的地方,否则我们要打开三个错误报告。
@ybungalobill:仅供参考,您不能在一条评论中通知两个人。
【参考方案1】:
不错的收获。我认为以我的拙见,ISO 委员会的意图是应该遵循 §3.4.2。 uninitialized_copy
的建议语义被错误地解释为好像需要调用逗号。并且实现不应该使用它(我会向 gcc 报告一个错误)。
【讨论】:
这也是我的解释。逗号重载太疯狂了,我认为它只是滑过了我们委员会成员的注意力。 是的,从那以后我提交了 PR 和 AFAIK,他们修复了标准,随后流行的实现删除了意外的逗号运算符调用。以上是关于实现是不是应该防止逗号重载?的主要内容,如果未能解决你的问题,请参考以下文章