views:

67

answers:

1

Hi @all,

I've got (probably) a simple question. When do I have to declare a function used in a template? The following code prints out (using gcc >=4.1):

init my A object

no init

Using gcc 4.0 the following code prints out:

init my A object

init my string object

#include <iostream>
#include <string>

template<typename T>
void init(T& t){
        std::cout << "no init" << std::endl;
}

// void init(std::string& t);

template <typename T>
void doSomething(T& t){
        init(t);
        // do some further stuff
}

void init(std::string& t){
        std::cout << "init my string object" << std::endl;
}


class A{

};

void init(A& t){
        std::cout << "init my A object" << std::endl;
}

int main(){
        A a;
        doSomething(a);
        std::string s("test");
        doSomething(s);
        return 0;
}

What is the difference between the usage of std::string and A? Shouldn't there be the same behaviour?

With the additional forward declaration it works fine, but when do I need it?

Cheers, CSpille

+4  A: 

Functions at the instantiation point are looked up only using argument dependent lookup (looking up functions in the namespaces associated with a function argument). Normal lookup is only done at the point of the template definition.

So for std::string, only the generic init function template is visible and called, since there is no specific one for it in namespace std. For A, the more specific function is found in the global namespace of A.

If you forward declare the string specific function to appear prior to doSomething, normal unqualified lookup finds it at the definition and uses it later on.

If you call init as follows, it inhibits argument dependent lookup, and will thus use the generic template for A too.

template <typename T>
void doSomething(T& t){
    (init)(t);
    // won't do ADL
}

(As a side-node: In that case, not only argument dependent lookup is inhibited at instantiation, but init won't be a dependent name in the first place - only non-parenthesized and unqualified function names are made dependent. Thus only non-ADL lookup at definition is done anyway and no lookup at instantiation is taken place what-so-ever, even if there would be a form different from ADL that would be done there.)

Johannes Schaub - litb
Great answer! thx! DANKE!Do you probably know, how this "(init)(t);" is called? non-ADL lookup?Are there other cases, when brackets around the function are useful?
CSpille
@CSpille, they are useful to inhibit a function-like macro invocation too. But inhibiting ADL is the only other purpose i know. As far as i know, wrapping the function name in parentheses doesn't have a special name :)
Johannes Schaub - litb