When answering this SO question, I found in the Standard (already C++03, still in C++11) that you can only use addresses as non-type template arguments if they're of the form & id-expression
(plus some exceptions).
But I couldn't answer why this is the case.
14.3.2 Template non-type arguments [temp.arg.nontype]
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 an 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, 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; [...]
(n3485, emphasis mine)
Example:
using TFoobar = int (*)();
template < TFoobar tp > struct foo_struct{};
int foobar() { return 42; }
constexpr TFoobar pFoobar = &foobar;
foo_struct < &foobar > o0; // fine
foo_struct < pFoobar > o1; // ill-formed
I guess it has something to do with the translation phases, namely the compiler doesn't know much about addresses. Yet, why isn't it allowed? Shouldn't it be possible for the compiler to use something similar to macro substitution to replace pFoobar
with &foobar
?