6

Consider this example:

template<int const& rf>
struct A{
  void fun(){
    constexpr int v = rf;  //#1
  }
};
int const object = 0;
int main(){
   A<object> a;
   a.fun();
}

GCC and Clang both agree that rf can be used as a constant expression.

However, in this case, rf is an id-expression. Hence, only the id-expression satisfies the following rule can it be used in a constant expression. The relevant rule is:
[expr.const#5.12]

an id-expression that refers to a variable or data member of reference type unless the reference has a preceding initialization and either

  • it is usable in constant expressions or
  • its lifetime began within the evaluation of E;

For the id-expression rf at #1, its lifetime does not begin within the evaluation of initialization. So, bullet 2 is not satisfied here. At the view of the declaration constexpr int v = rf; where id-expression rf does not have a preceding initialization. For bullet 1, the relevant rule says:

A constant-initialized potentially-constant variable V is usable in constant expressions at a point P if V's initializing declaration D is reachable from P and

  • V is constexpr
  • V is not initialized to a TU-local value, or
  • P is in the same translation unit as D.

rf is not constant-initialized since it neither has an initializer nor its default-initialization results in some initialization being performed. So, the id-expression rf used in #1 will violate [expr.const#5.12]. Hence, it cannot be used in #1. Actually, all compilers agree rf can be used in constant-expression(it also conforms to intuitive). However, the rule in the standard conflicts here. How to interpret this? Does it lack wording for a non-type template parameter that can be used in a constant expression?

xmh0511
  • 7,010
  • 1
  • 9
  • 36
  • Does this answer your question? [Reference as a non-type template argument](https://stackoverflow.com/questions/28662784/reference-as-a-non-type-template-argument) – dfrib Jun 25 '20 at 04:39
  • @dfri It's a subtle difference, in that question `X x2;` obviously ill-formed because of the id-expression's lifetime began before that and the standard explicitly said that. In my question, this point is similar to that, but it's considered to be well-formed by compilers. – xmh0511 Jun 25 '20 at 05:11
  • I was thinking about the `constexpr int& b` in the answer of the linked question: `A a{};` is well-formed, and afaics `b` in that context is similar to `B` in yours. I think the essential part is covered in the linked question: a variable of reference type is not an object; your part 2 examples contains objects, not only (constant expression) lvalue references. – dfrib Jun 25 '20 at 05:40
  • @dfri It's quite different with that. `constexpr int& b` is well-formed, because at that context, the `a` is a glvalue constant-expression which has static storage duration. I have modified my question to make it more easy to understand. The issue is that at `#1`, the id-expression of reference type would ill-formed according to the rule, but actually it's considered to be well-formed by compilers – xmh0511 Jun 25 '20 at 05:40
  • @dfri In that question , `A a{};` is well-formed, because firstly, `b` is an id-expression of reference type and has a preceding initialization , secondly, `it is initialized with a constant expression`, namely `a`, so it satisfied this rule, hence `A a{};` is well-formed since `b` is a glvalue constant-expression. This is all answers in that question but not here – xmh0511 Jun 25 '20 at 05:51
  • Ok, look forward to some answer/feedback from some language lawyer guru! – dfrib Jun 25 '20 at 05:54
  • @dfri The difference here is that, at point `#1`, `B` has no preceding initialization and it's lifetime has started but not within a evaluation of `#1`. – xmh0511 Jun 25 '20 at 05:55
  • 2
    @dfri Yes, I'm looking for these knowledge men. Please vote this question to make someone notice this question. In addition, I 70% sure this maybe a defect :-) – xmh0511 Jun 25 '20 at 05:57
  • "An expression e is a core constant expression unless the **evaluation** of e...", and look in [dcl.init.ref]/5 "The usual **lvalue-to-rvalue**, array-to-pointer, and function-to-pointer standard conversions are not needed, and therefore are suppressed, when such direct bindings to lvalues are done." lvalue-to-rvalue is what is usualy refered as the **evaluation**. The term is defined here:http://eel.is/c++draft/basic.exec#intro.execution-7. In the GCC documentation you may read that there the hole in the standard here: what is an evaluation. But it is accepted as is. – Oliv Jun 25 '20 at 07:03
  • Direct binding is not considered an evaluation, rather reference constexprness are governed by:http://eel.is/c++draft/expr.const#11.sentence-2. And if you want to understand it, hopefully you will consider a commity member someone knowledge and you should read its blog post: https://brevzin.github.io/c++/2020/02/05/constexpr-array-size/ – Oliv Jun 25 '20 at 07:06
  • And the standard you cite is too hold considering: http://eel.is/c++draft/expr.const#5.12.1, they are constantly fixing this part since at least 10 years. – Oliv Jun 25 '20 at 07:19
  • @Oliv No, to determine the identity of an object, the glvalue evaluation is used to do this. It's irrelevant whether the reference is directly binding or not. And part 2 prove that. – xmh0511 Jun 25 '20 at 12:57
  • Not sure if non-type template parameter is a variable (ofc it is not a data member) – Language Lawyer Jun 25 '20 at 16:07
  • @LanguageLawyer [Reference](https://timsong-cpp.github.io/cppwp/n4659/temp.param#4.3) should be, the others all prvalue. – xmh0511 Jun 26 '20 at 01:25
  • @LanguageLawyer This outcome prove that non-type `Reference` parameter is a variable. – xmh0511 Jun 28 '20 at 05:33
  • @LanguageLawyer I don't know whether template parameters are considered variables, but I think they should probably be defined not to be, since they don't have properties like lifetime and storage duration that variables are supposed to have. Worth opening up a core issue about IMHO. – Brian Bi Oct 02 '22 at 20:48
  • @BrianBi storage duration and lifetime are properties of objects and references. Not variables. Variables' properties are: scope, linkage etc. – Language Lawyer Oct 10 '22 at 08:55

0 Answers0