1
votes

Here is two-phase name lookup for template from iso-standard:

  • When looking for the declaration of a name used in a template definition, the usual lookup rules (6.4.1, 6.4.2) are used for non-dependent names.

  • The lookup of names dependent on the template parameters is postponed until the actual template argument is known

Sample codes:

#include <iostream>

void WithoutTemplate(int) {std::cout << "NonTemplate: int\n";}

template<typename T>
void WithTemplate(T) {std::cout << "no match\n";}

template<>
void WithTemplate(int) {std::cout <<"Template: int\n";}

template<typename T>
void test(T)
{
    WithTemplate(1.1);
    WithoutTemplate(1.1);
}

void WithoutTemplate(double) {std::cout << "nontemplate: double\n";}

template<>
void WithTemplate(double) {std::cout << "template: double\n";}

int main()
{
    test(1.1);
}

output:

template: double NonTemplate: int

There are two functions: WithTemplate and WithoutTemplate. The parameter 1.1 is non-dependent(though it is prvalue, which has no name? I assume it still obey non-dependent name's rules)

  • name lookup of WithoutTemplate meets 2-phase lookup, because when calling WithoutTemplate(1.1), void WithoutTemplate(double) is not visible. So the output NonTemplate: int is easy to understand.
  • However, the case which invokes full specialization function quite confuses me. its behaviour is opposite to the standard's rules(2-phase lookup). I thought it should output template: int

So, is there other name lookup rules for specialization? Or something else I misunderstand?

Here is what I have read:

1
Two-phase name lookup isn't relevant here; your template definition doesn't use any dependent names - the only name you use is std::cout which is fully qualified. (1.1 isn't a name.)Alan Stokes
@AlanStokes I think WithoutTemplate uses 2-phase name lookup here which also uses non-dependent name. So WithTemplate may also use it, but I'm not sure, so the question is stragety...Chen Li
The names looked up within test are non-dependent, so the normal rules apply. At the point where you call WithoutTemplate only one definition is visible, so that's the one that is called. (If you were to replace 1.1 with (T) 1.1 you might see different results.)Alan Stokes

1 Answers

4
votes

Your program has undefined behaviour, because you define the explicit specialization of WithTemplate<double> after it has been implicitly instantiated through the call WithTemplate(1.1). Explicit specializations must appear before any use of them that would cause instantiation - see e.g. http://en.cppreference.com/w/cpp/language/template_specialization.

So there's no point trying to reconcile the behaviour with what the standard says; the standard explicitly says nothing about what should happen here.