Reputation: 5209
As seen in this question, the OP was trying to make following statement iterate over the numbers.
for (int n : 10)
cout << n << endl;
Obviously, wrong syntax, because int
has no begin()
and end()
methods. But it should be possible. Based on documentation of range-based for loop this is important.
for
(
range_declaration:
range_expression)
loop_statementrange_expression - any expression that represents a suitable sequence (either an array or an object for which begin and end member functions or free functions are defined, see below) or a braced-init-list.
And following
The above syntax produces code equivalent to the following (
__range
,__begin
and__end
are for exposition only):{ // until C++17 auto && __range = range_expression ; for (auto __begin = begin_expr, __end = end_expr; __begin != __end; ++__begin) { range_declaration = *__begin; loop_statement } }
With clarification of begin_expr and end_expr are:
begin_expr and end_expr are defined as follows:
- If range_expression is an expression of array type, then [...]
- If range_expression is an expression of a class type C [...]
- Otherwise, begin_expr is
begin(__range)
and end_expr isend(__range)
, which are found via argument-dependent lookup (non-ADL lookup is not performed).
In our case range_expression is 10
, which is not of array type nor of a class type, so last bullet should take effect. So we provide these functions
auto begin(int) {
return boost::counting_iterator<int>(0);
}
auto end(int n) {
return boost::counting_iterator<int>(n);
}
(boost::counting_iterator
could be easily implemented). And it should work, right? However it fails with
main.cpp: In function 'int main()':
main.cpp:17:18: error: 'begin' was not declared in this scope
for (int t : 10)
^~
main.cpp:17:18: note: suggested alternatives:
main.cpp:5:6: note: 'begin'
auto begin(int) {
^~~~~
In file included from /usr/local/include/c++/7.2.0/vector:66:0,
from main.cpp:1:
/usr/local/include/c++/7.2.0/bits/range_access.h:105:37: note: 'std::begin'
template<typename _Tp> const _Tp* begin(const valarray<_Tp>&);
^~~~~
(and same message for end
). However, if I change the range-based for loop according to description, I get following, which works.
{
auto && __range = 10;
for (auto __begin = begin(__range), __end = end(__range); __begin != __end; ++__begin) {
int t = *__begin;
std::cout << t << std::endl;
}
}
Upvotes: 3
Views: 227
Reputation: 473272
The key phrase is:
which are found via argument-dependent lookup (non-ADL lookup is not performed)
int
has no namespace. No, not even the global namespace. As such, lookup based on the namespace finds nothing.
To be more specific to the specification, [basic.lookup.argdep]/2.1 says:
If T is a fundamental type, its associated sets of namespaces and classes are both empty.
And since there are no associated namespaces or classes, ADL doesn't work.
This would be better handled by a user-defined literal that returns a counting range. So you would type 10_rng
, and that would yield a counting range.
Upvotes: 8