As written in the Standard for templates, one of the non-type template parameters can be a pointer to object. For exapmple:
template <int* x>
void f()
{}
However when giving the argument during instantiation, only pointers to objects with external linkage are allowed. Why? Why doesn't the Standard allow to instantiate non-type template with a pointer to object with internal linkage?
I found in other topics on StackOverflow some explanations but it is not clear for me:
A non-type template argument provided within a template argument list is an expression whose value can be determined at compile time. Such arguments must be: constant expressions, addresses of functions or objects with external linkage, or addresses of static class members.
So if I have static const int x = 10;
in a global scope, is the address of this object determined at compile time ?
Also I found in comments explanation:
You don't know what the call-stack looks like at compile time. Before your function, there could've been called 10 other or 3 others or however many other, so the address on the stack, at which the string gets created can change from call to call. When you have an object with external linkage, its address is fixed during compilation/linkage.
How can be changed the address of static const int x = 10;
defined in a global scope?
It would be great to understand what happens under the hood.
In C++11 the requirements were relaxed (with further clarifications in C++14), now [temp.arg.nontype]/1
reads:
A template-argument for a non-type, non-template template-parameter shall be one of:
(...)
— a constant expression (5.19) that designates the address of a complete object with static storage duration and external or internal linkage or a function with external or internal linkage, including function templates and function template-ids but excluding non-static class members, expressed (ignoring parentheses) as&
id-expression, where the id-expression is the name of an object or function, except that the&
may be omitted if the name refers to a function or array and shall be omitted if the corresponding template-parameter is a reference
So in C++11 this compiles, as you want:
template<int* i> void f(){};
static int x; // even without const
int main() {
f<&x>();
}