C++0x 标准工作草案陈述(第6.5.4 节)以下关于隐含在基于范围的 for 循环中的 begin() 和 end() 调用:
'begin' 和 'end' 使用参数相关查找 (3.4.2) 进行查找。出于此名称查找的目的,命名空间 std 是一个关联的命名空间。
按照我的阅读方式,这意味着为调用 begin() 和 end() 设置的重载解决方案包括以下所有内容:
- begin() 和 end() 的所有重载都在使用基于范围的 for 循环的位置范围内(特别是,全局命名空间中的所有重载都将在范围内)
- 命名空间 std 中 begin() 和 end() 的所有重载
- 与其参数关联的其他命名空间中的 begin() 和 end() 的所有重载
那是对的吗?
g++ 4.6 的行为似乎与这种解释不一致。对于此代码:
#include <utility>
template <typename T, typename U>
T begin(const std::pair<T, U>& p);
template <typename T, typename U>
U end(const std::pair<T, U>& p);
int main()
{
std::pair<int*, int*> p;
for (int x : p)
;
}
它给出了以下错误:
adl1.cpp: In function 'int main()':
adl1.cpp:12:18: error: No match for 'begin(pair<int *, int *> &)'
adl1.cpp:12:18: candidate is:
/usr/local/lib/gcc/i686-pc-linux-
gnu/4.6.0/../../../../include/c++/4.6.0/initializer_list:86:38: template<
class _Tp> constexpr const _Tp * begin(initializer_list<_Tp>)
adl1.cpp:12:18: error: No match for 'end(pair<int *, int *> &)'
adl1.cpp:12:18: candidate is:
/usr/local/lib/gcc/i686-pc-linux-
gnu/4.6.0/../../../../include/c++/4.6.0/initializer_list:96:36: template<
class _Tp> constexpr const _Tp * end(initializer_list<_Tp>)
这表明它只考虑命名空间 std 中的重载,而不考虑全局命名空间中的重载。
但是,如果我使用在全局命名空间中声明的我自己的 pair 类,它编译得很好:
template <typename T, typename U>
struct my_pair
{
T first;
U second;
};
template <typename T, typename U>
T begin(const my_pair<T, U>& p);
template <typename T, typename U>
U end(const my_pair<T, U>& p);
int main()
{
my_pair<int*, int*> p;
for (int x : p)
;
}
作为最终测试,我尝试将 my_pair 放在单独的命名空间中:
namespace my
{
template <typename T, typename U>
struct my_pair
{
T first;
U second;
};
}
template <typename T, typename U>
T begin(const my::my_pair<T, U>& p);
template <typename T, typename U>
U end(const my::my_pair<T, U>& p);
int main()
{
my::my_pair<int*, int*> p;
for (int x : p)
;
}
我再次得到错误:
adl3.cpp: In function 'int main()':
adl3.cpp:22:18: error: 'begin' was not declared in this scope
adl3.cpp:22:18: suggested alternative:
adl3.cpp:14:35: 'begin'
adl3.cpp:22:18: error: 'end' was not declared in this scope
adl3.cpp:22:18: suggested alternative:
adl3.cpp:17:33: 'end'
因此,它似乎只考虑命名空间 std 和其他相关命名空间中的重载,而不考虑调用站点范围内的重载(我上面列表中的第一个要点)。
这是一个 gcc 错误,还是我误解了标准?
如果是后者,这是否意味着不可能将 std::pair 对象视为基于范围的 for 循环中的范围(不重载 std::begin() 和 std::end(),如果我不是错误是不允许的)?