This is an extension to this question from 2011: Range-based for loops and ADL
Using Visual Studio 2015, I'm not able to make a range-based for loop for a custom container using Argument Dependent Lookup (ADL).
I have made a very simple test case below with a custom container:
#include <vector>
namespace Foo
{
template <typename T>
class Container
{
public:
std::vector<T> values;
};
}
template <typename T>
typename std::vector<T>::iterator begin(Foo::Container<T>& foo)
{
return foo.values.begin();
}
template <typename T>
typename std::vector<T>::iterator end(Foo::Container<T>& foo)
{
return foo.values.end();
}
Using this container and ADL, the following test compiles perfectly fine:
int main(int argc, char* argv[])
{
Foo::Container<int> values;
for (auto it = begin(values); it != end(values); ++it)
{
...
}
return 0;
}
As it should. I'm not sure if ADL is even being utilized here, but regardless, it makes sense. From MSDN documentation, we have:
Keep in mind these facts about range-based for:
Automatically recognizes arrays.
Recognizes containers that have .begin() and .end().
Uses argument-dependent lookup begin() and end() for anything else.
From what I understand of ADL, and the documentation above, the following should also compile:
int main(int argc, char* argv[])
{
Foo::Container<int> values;
for (auto value : values)
{
...
}
return 0;
}
But it doesn't. Instead, I get the following errors:
error C3312: no callable 'begin' function found for type 'Foo::Container<int>'
error C3312: no callable 'end' function found for type 'Foo::Container<int>'
So what's going on here? Is my interpretation of ADL incorrect, or is this a bug with MSVC 14.0 Compiler?
Range-based for loop in C++ is added since C++ 11. It executes a for loop over a range. Used as a more readable equivalent to the traditional for loop operating over a range of values, such as all elements in a container.
Use the range-based for statement to construct loops that must execute through a range, which is defined as anything that you can iterate through—for example, std::vector , or any other C++ Standard Library sequence whose range is defined by a begin() and end() .
The "for" loop For loops can iterate over a sequence of numbers using the "range" and "xrange" functions. The difference between range and xrange is that the range function returns a new list with numbers of that specified range, whereas xrange returns an iterator, which is more efficient.
Range-Based 'for' loops have been included in the language since C++11. It automatically iterates (loops) over the iterable (container). This is very efficient when used with the standard library container (as will be used in this article) as there will be no wrong access to memory outside the scope of the iterable.
You have to place both begin
and end
into Foo
namespace for ADL to work. This is because ADL will look into namespaces of corresponding arguments to search definitions of begin
and end
.
namespace Foo
{
template <typename T>
class Container
{
public:
std::vector<T> values;
};
template <typename T>
typename std::vector<T>::iterator begin(Foo::Container<T>& foo)
{
return foo.values.begin();
}
template <typename T>
typename std::vector<T>::iterator end(Foo::Container<T>& foo)
{
return foo.values.end();
}
}
UPD: The reason why begin
and end
from global namespace are not considered is because of the updated standard saying that begin
and end
are looked up in the associated namespaces but ordinary unqualified lookup is not performed. This is a consequence of bug fix in the standard (http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1442).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With