实现是否应该防止逗号过载?
例如,uninitialized_copy
在标准中定义为:
效果:
for (; 第一个 != 最后一个; ++结果, ++第一个) ::new (static_cast
(&*结果)) 类型名 iterator_traits ::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 不会。
不幸的是,我找不到标准在哪里禁止迭代器类型的运算符重载。相反,它禁止实现执行上述调用[global.functions]:
除非另有说明,标准库中的全局函数和非成员函数不得使用通过依赖于参数的名称查找 (3.4.2) 找到的其他命名空间中的函数。
那么这四个方面谁错了:MSVC、GCC、ISO 还是我? (选择一项)
For example uninitialized_copy
is defined in the standard as:
Effects:
for (; first != last; ++result, ++first) ::new (static_cast<void*>(&*result)) typename iterator_traits<ForwardIterator>::value_type(*first);
If understood literally, this is a requirement to call operator ,(ForwardIterator, InputIterator)
. And in fact this code prints Hello world!
ten times:
#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));
}
However, for most other algorithms the standard gives the description in prose. E.g. for copy
there's no requirement for operator ,
to be called. But if I change
uninitialized_copy(X(a), X(a+10), X(b));
in the above code to
copy(X(a), X(a+10), X(b));
then Hello world!
is still printed ten times. The said results are observable in both, VS2005 and GCC 4.3.4. However, if I write
mismatch(X(a), X(a+10), X(b));
instead, then VS2005 prints Hello world!
ten times but GCC does not.
Unfortunately I couldn't find where the standard prohibits operator,
overloading for iterator types. On the contrary, it prohibits the implementations to do calls as above [global.functions]:
Unless otherwise specified, global and non-member functions in the standard library shall not use functions from another namespace which are found through argument-dependent name lookup (3.4.2).
So who of the four parties is wrong: MSVC, GCC, ISO or me? (Choose one)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
不错的收获。我认为,以我的拙见,ISO 委员会的意图是应遵循 §3.4.2。
uninitialized_copy
的建议语义被错误地解释为需要调用逗号。并且实现不应该使用它(顺便说一句,我会向 gcc 报告错误)。Nice catch. I think in my humble opinion that the ISO committee's intention was that §3.4.2 should be followed. The suggested semantics of
uninitialized_copy
is wrongly interpreted as if requiring the comma to be called. And implementations should not be using it (I'd report a bug to gcc btw).