Range for Loop and ADL

This is an extension of this question from 2011: Range for loops and ADL

Using Visual Studio 2015, I cannot create a range-based loop for a custom container using search argument-dependent (ADL).

I 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 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 be. I'm not sure that ADL is used even here, but despite this, it makes sense. From the MSDN Documentation :

Keep these facts in mind about the range for:

  • Automatically recognizes arrays.

  • Recognizes containers with the names .begin () and .end ().

  • Uses an argument-dependent search for begin () and end () for anything else.

From what I understand in ADL and the above documentation, you must also compile:

 int main(int argc, char* argv[]) { Foo::Container<int> values; for (auto value : values) { ... } return 0; } 

But this is not so. Instead, the following errors occur:

 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 is going on here? Is my ADL interpretation incorrect or is it an error with the MSVC 14.0 compiler?

+6
source share
1 answer

You must put both begin and end in the Foo namespace for ADL to work. This is because ADL will look up the namespaces of the corresponding arguments to search for begin and end definitions.

 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 that begin and end not considered from the global namespace is due to an updated standard saying that begin and end looked up in the corresponding namespaces but normal unqualified searches are not performed. This is the result of fixing bugs in the standard ( http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1442 ).

+7
source

All Articles