Pregunta

I tried to consult the standard on the resolution of do_run, and found "For the part of the lookup using unqualified name lookup (3.4.1) or qualified name lookup (3.4.3), only function declarations from the template definition context are found". What exactly is the context?

In the following example, do_run(int) somehow "hides" do_run(domain::mystruct), and the compiler complains that o can't be converted to int. If I comment out do_run(int), do_run(domain::mystruct) becomes visible to run, and the code is compiled. Is this behavior related to the "context" referred to in the standard? Seems to me both do_run(int) and do_run(domain::mystruct) should be visible to (resolvable) run.

namespace domain {
    struct mystruct { };
}

void do_run(domain::mystruct) { cout << "do_run(domain::mystruct)" << endl; } 

namespace lib { namespace details {

    template <class T>
    class runner { 
    public:
        void run(T t) { do_run(t); }
    };

    void do_run(int) { cout << "do_run(int)" << endl; } 
}}

int main() {
    domain::mystruct o;
    lib::details::runner<domain::mystruct> r;
    r.run(o);
    return 0;
}

In the presence of do_run(int), I need an extra step to bring do_run(domain::mystruct) into the "context". there're three ways:

  1. put do_run(domain::mystruct) in namespace domain.
  2. put do_run(domain::mystruct) in namespace lib::details.
  3. add using ::do_run inside namespace lib::details.

So I deduced the context is namespace lib::details and namespace domain?

Compiler VS2010

¿Fue útil?

Solución

The look-up depends on whether it is a dependent name or not. Since your function call depends on the template argument type T (through being called using the object t of this type), it is a dependent name.

Non-dependent names are just looked up in the context where the template is defined. Anything relating to the actual instantiation is not taken into consideration: Since the name is determined as not depending on the template argument, it wouldn't make sense to take the instantiation into account. This is phase I look-up.

Dependent function names are looked up taking the instantiation into account. This uses all arguments and determines associated namespaces to look up functions in these associated namespace only. For built-in types, the associated namespace added is the global namespace. For other types, the associated namespaces added are the namespace they live in plus all enclosing namespace. In addition, the associated namespace of things visible from the class definition are added: the associated namespaces of base classes, for templates the namespaces of the template arguments, etc. This is phase II look-up and also called argument dependent look-up (I think the terms are not entirely identical and the details are not as easy as described above, of course).

In the code you quoted, the do_run() function in the global scope is, obviously, found for lib::details::runner<domain::mystruct> as it is in the global namespace. It would also be found if it were moved to domain. The do_run() method in namespace lib::details is not found in an instantiation lib::details::runner<int>, however: the associated namespaces for int are only the global namespace but the function isn't there and it isn't looked up until instantiation because it is a dependent name.

That said, my understanding is that MSVC++ doesn't implement two-phase name look-up the way it is specified but I don't know in which ways it deviates.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top