This program implements a compile-time type-map supporting insertion at local scope together with persistence out to global scope. Clang happily runs it, although GCC 4.9.2 mistakes the friend declaration for a nonstatic member. Is it conforming?
[temp.point] §14.6.4.1 says “the point of instantiation for [a class template] specialization immediately precedes the namespace scope declaration or definition that refers to the specialization,” and [temp.inject] §14.6.5 says “the names of [a class template specialization’s] friends are treated as if the specialization had been explicitly declared at its point of instantiation.”
According to the points of instantiation of the functions that form the type-map, they are all available before the beginning of main. So far, so good. But that also means that the contents of the map could just as well be retrieved before they are injected — going backwards in time, if you like. (Clang doesn’t like that quite as much.)
This is a very useful construct. Perhaps finer sequencing should be defined for points of instantiation, so as to allow it. Otherwise, try and poke a hole in it without bringing down the whole house of cards ;) .
template< typename k >
struct t {
friend auto leak( t );
template< typename v >
struct m {
friend auto leak( t ) { return v{}; }
};
};
struct hi { hi() { std::cout << "hi\n"; } };
struct bi { bi() { std::cout << "bi\n"; } };
int main() {
t< int >::m< hi >{};
decltype( leak( t< int >{} ) ) {};
t< char >::m< bi >{};
decltype( leak( t< char >{} ) ) {};
}