Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Range-Based For Loop and ADL

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?

like image 643
Zeenobit Avatar asked Sep 20 '15 16:09

Zeenobit


People also ask

What is a range-based loop?

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.

When would you use a range-based loop?

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() .

What is the difference between for range loop and?

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.

Does range-based for loop use iterator?

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.


1 Answers

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).

like image 57
Pavlo Mur Avatar answered Sep 22 '22 11:09

Pavlo Mur