I am playing a bit with static polymorphism, I'm calling a function which internally calls the "right" specialized function depending on the type of the initial argument (basically I'm doing tagging). Here is the code:
#include <iostream>
using namespace std;
// tags
struct tag1{}; 
struct tag2{}; 
// the compliant types, all should typedef tag_type
struct my_type1
{
    using tag_type = tag1;
};
struct my_type2
{
    using tag_type = tag2;
};
// static dispatch via tagging
template <typename T>
void f(T) 
{
    cout << "In void f<typename T>(T)" << endl;
    // why can I call f_helper without forward definition?!?        
    f_helper(typename T::tag_type{}); 
}
int main()
{
    my_type1 type1;
    my_type2 type2;
    // how does f below knows about f_helper ?!?!
    // even after instantiation f_helper shouldn't be visible!
    f(type1); 
    f(type2);
}
// helper functions
void f_helper(tag1) 
{
    cout << "f called with my_type1" << endl;
}
void f_helper(tag2)
{
    cout << "f called with my_type2" << endl;
}
So, f(T) is called with a parameter my_type1 or my_type2 that internally must typedef tag_type with the appropriate tag tag1/tag2. Depending on this internal tag_type, the "right" wrapper is then called, and this decision is made of course at compile time. Now I really don't understand why this code IS working? Why don't we need to forward-declare f_helper? I first had the wrappers defined before main (and after f), and I though ok, this makes sense, you don't need to forward declare because the compiler instantiate the template only when f(type1); is called (in main()), before it doesn't know the type T, so at the time of instantiation the compiler knows f_wrapper. 
But as you see, even if I declare the wrappers AFTER main(), the code still works. Why is this happening? I guess the question is a bit strange, asking why a code works :)
EDIT
The code continues to compile even in gcc5 and gcc HEAD 6.0.0.
                        
f_helper(typename T::tag_type{})is a type-dependent expression becauseT::tag_typeis a dependent type. This means thatf_helperdoesn't need to be visible untilf<T>is instantiated due to two phase lookup.EDIT: I'm pretty sure that this is actually undefined behaviour. If we look at 14.6.4.2 [temp.dep.candidate] we see this passage:
The last paragraph to me indicates this is undefined behaviour. The
function call that depends on a template parameterhere isf_helper(typename T::tag_type{}).f_helperisn't visible whenfis instantiated, but it would be if we performed name lookup after all translation units have been compiled.