The example below attempts to use a variable of reference type as an argument for a non-type template parameter (itself of reference type). Clang, GCC and VC++ all reject it. Bu
It is correct saying that the name of a reference is an id-expression, though; the id-expression doesn't refer to whatever the reference is referencing, but the reference itself.
int a = 0;
int& ref = a; // "ref" is an id-expression, referring to `ref` - not `a`
You are quoting the relevant sections of the standard in your post, but you left out the most important part (emphasize mine):
14.3.2p1 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 a complete object with static sturage 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 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; ...
Note: In earlier drafts "where id-expression is the name of an object or function" isn't present; it was addressed by DR 1570 - which undoubtedly makes the intent more clear.
You are absolutely correct; the reference itself has reference type, and can merely act as an object when part of an expression.
5p5 Expressions [expr]
If an expression initially has the type "reference to
T
" (8.3.2, 8.5.3), the type is adjusted toT
prior to any further analysis. The expression designates the object or function denoted by the reference, and the expression is an lvalue or an xvalue, depending on the expression.
It is very important to note that the constant expression ("that designates the address of a complete object...") must be one of &id-expression
, or id-expression
.
Even though a constant-expression, that isn't just an id-expression, might refer to an object with static storage duration, we cannot use it to "initialize" a template-parameter of reference- or pointer type.
Example Snippet
template
struct A { };
int a = 0;
constexpr int& b = (0, a); // ok, constant-expression
A<(0, a)> c = {}; // ill-formed, `(0, a)` is not an id-expression
Note: This is also a reason behind the fact that we cannot use string-literals as template-arguments; they are not id-expressions.