Search code examples
c++templatestuplesc++11argument-dependent-lookup

getting an element from a tuple


Possible Duplicate:
Why doesn't ADL find function templates?

Calling get does not seem to invoke argument dependent lookup:

auto t = std::make_tuple(false, false, true);
bool a = get<0>(t);        // error
bool b = std::get<0>(t);   // okay

g++ 4.6.0 says:

error: 'get' was not declared in this scope

Visual Studio 2010 says:

error C2065: 'get': undeclared identifier

Why?


Solution

  • It's because you attempt to explicitly instantiate get function template, by providing 0 as template argument. In case of templates, ADL works if a function template with that name is visible at the point of the call. This visible function template only helps triggering ADL (it may not be used actually) and then, a best matching can be found in other namespaces.

    Note that the function template which triggers (or enable) ADL, need not to have definition:

    namespace M
    {
        struct S{};
    
        template<int N, typename T>
        void get(T) {}     
    }
    
    namespace N
    {
       template<typename T>
       void get(T); //no need to provide definition
                    // as far as enabling ADL is concerned!
    } 
    
    void f(M::S s)
    {
       get<0>(s); //doesn't work - name `get` is not visible here 
    }
    
    void g(M::S s)
    {
       using N::get; //enable ADL
       get<0>(s); //calls M::get
    }
    

    In g(), the name N::get triggers ADL when calling get<0>(s).

    Demo : http://ideone.com/83WOW


    C++ (2003) section §14.8.1/6 reads,

    [Note: For simple function names, argument dependent lookup (3.4.2) applies even when the function name is not visible within the scope of the call. This is because the call still has the syntactic form of a function call (3.4.1). But when a function template with explicit template arguments is used, the call does not have the correct syntactic form unless there is a function template with that name visible at the point of the call. If no such name is visible, the call is not syntactically well-formed and argument-dependent lookup does not apply. If some such name is visible, argument dependent lookup applies and additional function templates may be found in other namespaces.

    [Example:

    namespace A {
         struct B { };
         template<int X> void f(B);
    }
    namespace C {
         template<class T> void f(T t);
    }
    void g(A::B b) {
         f<3>(b);    //ill-formed: not a function call
         A::f<3>(b); //well-formed
         C::f<3>(b); //ill-formed; argument dependent lookup
                     // applies only to unqualified names
    
        using C::f;
         f<3>(b); //well-formed because C::f is visible; then
                  // A::f is found by argument dependent lookup
    }
    

    —end example] —end note]