To start, there is temp.arg.nontype#2:
A template-argument for a non-type template-parameter shall be a converted constant expression ([expr.const]) of the type of the template-parameter.
[Note 1: If the template-argument is an overload set (or the address of such, including forming a pointer-to-member), the matching function is selected from the set ([over.over]). — end note]
We can then follow that to expr.const#10:
A converted constant expression of type T is an expression, implicitly converted to type T, where the converted expression is a constant expression and the implicit conversion sequence contains only ...
From that rule, we can see that the variable cp
can't possibly be a constant expression since it is not even potentially-constant according to expr.const#3:
A variable is potentially-constant if it is constexpr or it has reference or const-qualified integral or enumeration type.
So cp
is not a valid template-argument for a non-type template parameter, and you get an error.
Note that this is where the apparent inconsistency arises with ci
. Since ci
has a const-qualified integral type, it can be used as a template-argument for a non-type template parameter.
Similarly, all the other calls to f
are allowed as well, since the template-argument in each case is a constant expression:
g
is a function with external linkage, and so its address is a constant expression.
5
is a constant integral expression.
cexprp
and cexpri
are both constexpr
variables.