// translation unit 1: template<class T> void f(T*); void g(int* p) { f(p); // calls f<int>(int*) }
// translation unit 2: template<class T> void f(T); void h(int* p) { f(p); // calls f<int*>(int*) }
template<class T> void f(); template<int I> void f(); // OK: overloads the first template // distinguishable with an explicit template argument list— end note
template <int I, int J> A<I+J> f(A<I>, A<J>); // #1 template <int K, int L> A<K+L> f(A<K>, A<L>); // same as #1 template <int I, int J> A<I-J> f(A<I>, A<J>); // different from #1— end example
template <int I, int J> void f(A<I+J>); // #1 template <int K, int L> void f(A<K+L>); // same as #1 template <class T> decltype(g(T())) h(); int g(int); template <class T> decltype(g(T())) h() // redeclaration of h() uses the earlier lookup… { return g(T()); } // … although the lookup here does find g(int) int i = h<int>(); // template argument substitution fails; g(int) // was not in scope at the first declaration of h() // ill-formed, no diagnostic required: the two expressions are functionally equivalent but not equivalent template <int N> void foo(const char (*s)[([]{}, N)]); template <int N> void foo(const char (*s)[([]{}, N)]); // two different declarations because the non-dependent portions are not considered equivalent template <class T> void spam(decltype([]{}) (*s)[sizeof(T)]); template <class T> void spam(decltype([]{}) (*s)[sizeof(T)]);— end example
// guaranteed to be the same template <int I> void f(A<I>, A<I+10>); template <int I> void f(A<I>, A<I+10>); // guaranteed to be different template <int I> void f(A<I>, A<I+10>); template <int I> void f(A<I>, A<I+11>); // ill-formed, no diagnostic required template <int I> void f(A<I>, A<I+10>); template <int I> void f(A<I>, A<I+1+2+3+4>);— end note