Стандартный рабочий проект C ++ 0x заявляет (раздел 6.5.4) о вызовах begin () и end (), которые неявны в цикле for на основе диапазона:
'begin' и 'end' ищутся с помощью аргумент-зависимого поиска (3.4.2).Для целей этого поиска имен пространство имен std является связанным пространством имен.
То, как я это читаю, означает, что разрешение перегрузки, установленное для вызовов begin () и end (), включает всеиз следующего:
- все перегрузки begin () и end (), которые находятся в области действия в месте, где используется цикл for на основе диапазона (в частности, все перегрузки в глобальном пространстве имен будутнаходиться в области видимости)
- все перегрузки begin () и end () в пространстве имен std
- все перегрузки 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, а неперегрузки в глобальном пространстве имен.
Если, однако, я использую свой собственный класс пар, объявленный в глобальном пространстве имен, он прекрасно компилируется:
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'
Так что, кажется, он рассматривает перегрузки only в пространстве имен std и другие связанныепространства имен, а не перегрузки, которые находятся в области действия на сайте вызовов (первый пункт в моем списке выше).
Это ошибка gcc, или я неправильно интерпретирую стандарт?
Еслипоследнее, означает ли это, что невозможно обработать объект std :: pair как диапазон в цикле for, основанном на диапазоне (без перегрузки std :: begin () и std :: end (), что, если я не ошибаюсьне допускается)?