Firstly, some standard's quoted passage
If a template specialization X is referenced in a context that depends on a template-parameter of some surrounding template Y, the given point of instantation depends on the point of instantation of Y.
If X is a function template specialization, the point of instantiation is that of Y.
If X is a class template specialization, the point of instantiation is immediately before the point of instantiation of Y.Otherwise, the given point of instantiation is tied to the location of the namespace scope declaration/definition (D) which contains the statement referring to X.
If X is a function template specialization, the point of instantiation is immediately after D.
If X is a class template specialization, the point of instantiation is immediately before D.
Some code here
#include <iostream>
template<int N>
struct state {
friend auto call(state<N>);
};
template<int N>
struct add_state {
friend auto call(state<N>) {
return N;
}
};
template<typename T, int N>
T show() {
add_state<N> d;
return T{};
}
template<typename T,int N>
class data {
public:
T c = show<T,N>();
};
#1,#3,#2
int main() {
data<int, 0> t;
call(state<0>{});
}
So, according to the above rules, when instantiating class data<int, 0>
, then the point of instantiation is at #1.
Then show<T,N>
depends on template class data's template parameters. So the point of instantiation for show<int,0>
is at #2.
Then add_state<N>
depends on template function show's template parameters. So according to the rules, the point of instantiation for add_state<0>
is at #3.
At #3 auto call(state<0>)
has been defined, call(state<0>{})
should be linked but in the fact, the compiler reports errors as follows:
clang:
main.cpp:24:2: error: function 'call' with deduced return type cannot be used before it is defined
call(state<0>{});
^
main.cpp:4:14: note: 'call' declared here
friend auto call(state<N>);
^
1 error generated.
g++:
main.cpp: In function ‘int main()’:
main.cpp:24:17: error: use of ‘auto call(state<0>)’ before deduction of ‘auto’
call(state<0>{});
^
Why? Does my understand about the point of instantiation has some mistakes? If not, why does the compiler report these errors?
show
is a function template, it reuses #1, and #3 precedes that. – Davis Herringshow<int,0>
is instantiated at the end of your translation unit, the definition ofcall(state<0>)
will be after the use incall(state<0>{});
. [temp.point]/5 also forbids "two different points of instantiation [to] give a template specialization different meanings according to the one-definition rule", although I don't know whether this includes this scenario. – walnutshow
to force the instantiation of the body: godbolt.org/z/jEuQ_k – walnut