3

There has been lots of questions/answers pertaining questions to constexpr expression but i have a question which is pretty close to other question but slightly different in another sense. Anyway here it goes.

#include <iostream>
using namespace std;
                       
constexpr int x = 1; // TAG A

int main() {
   constexpr int &xf = x; // TAG B error out
   const int &xf1 = x; // TAG C works
   constexpr int const &xf2 = x; // TAG D works
   return 0;
}

Error:

Binding reference of type 'int' to value of type 'const int' drops 'const' qualifier [reference_bind_drops_quals]

Comments:

  1. TAG A clearly shows x is const int. Accordingly to the C++ Primer 5th Edition on page section 2.44 "Variables declared as constexpr are implicitly const and must be initialized by constant expressions:". So this is good.
  2. TAG B --> error message implies that the constexpr did not implicitly "const" the variable xf. Hence xf is int &. This contradict TAG A. Why?
  3. TAG C --> This is the usual reference to const
  4. TAG D --> Additional "const" added to make it a const reference due to how it behaves in TAG B.

Is there a difference in the word "reference to a const" and "const reference"?
it seems reference to const means reference is referring to a const object while not allowing to make modification while "const reference" is that the reference is const but it can point to either const or non-const objects.

This is one big confusing thing.

1201ProgramAlarm
  • 32,384
  • 7
  • 42
  • 56
yapkm01
  • 3,590
  • 7
  • 37
  • 62

2 Answers2

0

The constexpr in B refers to the variable xf, not the type (int & constexpr xf;, although I don't know if that will compile). The variable xf is a constexpr and it has type int &. This is why trying to bind it to x fails.

1201ProgramAlarm
  • 32,384
  • 7
  • 42
  • 56
  • Thx but i thought for reference there is only lower const level. A pointer can have top and lower const but not reference. – yapkm01 May 25 '21 at 22:49
  • @yapkm01 I see that is a bit confusing. I've removed iit. – 1201ProgramAlarm May 25 '21 at 22:51
  • from what i understand the constexpr will implicitly add the const qualifier to it. hence it will be const int &xf and not int &xf – yapkm01 May 25 '21 at 23:39
  • why is constexpr int x=1; having type .. const int and not int? constexpr int x=1 clearly changes the type. doesn't this contracdict the explanation above? – yapkm01 Sep 11 '21 at 22:08
0

Is there a difference in the word "reference to a const" and "const reference"

Yes, conceptually, but "const reference" logically collapses to just "reference" because technically all references are constant. This is also why the language doesn't let you declare references as explicitly const. That said, there are still cases in the language where it could make sense to talk about a "const reference". Consider the following example:

typedef int &intref;

int main() {
    int x = 0;
    const intref xf = x;
    return 0;
}

In this case, xf is in fact a const reference (not a reference to const), and the declaration is still valid. This will give you a warning about the const qualifier being ignored, but it will still compile and run. This illustrates why it's still important to be extremely rigorous about sticking to declaration order rules.

The next very important piece of information to understand for this declaration is the application of the constexpr keyword, and exactly what it means when we say it "implies const". The constexpr keyword always refers to the object in the declaration (not the type), so when we say constexpr implies const, it means in a hand-wavy sense, you can omit the const keyword on the inner most part of a constexpr declaration (xf in this example) because it's redundant. In the special case of a reference, it's not only redundant, it's not allowed. You could argue that the compiler throwing an error is a little bit unnecessary given that you can get around it with a typedef, but the principle still applies, as does the rule for the application of the missing const.

Putting all this together, in your example, you can read declaration B out loud as something like:

"xf is a constexpr which is a reference (which is by definition const, and therefore no need to imply const) to an integer."

But here we have a problem, in that we're trying to declare a reference to a non-constant object and assign it to a constant object. This is exactly what the compiler complains about.

See also this.

Jon Reeves
  • 2,426
  • 3
  • 14
  • The definition of const you mentioned is reference are not allowed to repoint to different object. I get that. i see constexpr int &xf = x; no different that const int &x; The constness here is reference are not allowed to modify the pointed objects since the latter is a const. i just don't understand why constexpr int &xf = x; does not equate to const int &xf=x since according to C++ Primer constexpr will implicitly implies const. – yapkm01 May 25 '21 at 23:22
  • You mentioned "But here we have a problem, in that we're trying to declare a reference to a non-constant object ..." --> this is the confusion part. I see it as a declare a reference to a const .. because constexpr int &xf = x .. i see it as const int &xf=x; i think the root of my confusion is why constexpr int &xf does not translate to const int &xf; – yapkm01 May 25 '21 at 23:26
  • It's a very subtle point, and I do understand the confusion. Let me spend some time trying to reformulate the answer a bit, hopefully it will help. I'm not sure I can put enough info in these comment blocks. – Jon Reeves May 25 '21 at 23:56
  • i understand the typedef example you use. also i understand this part .. ""xf is a constexpr which is a reference (which is by definition const, and therefore no need to imply const) to an integer." So using equivalent reading constexpr int x = 1; (TAG A) .. it'll be "x is a constexpr which is an int and it implied (added) const implicitly. So the difference here is for xf it does not need to add the const because it is redundant but not for x. Can you confirm if my assessment is correct? Thx – yapkm01 May 26 '21 at 03:33
  • That's correct @yapkm01. Another way to think of it might be: the compiler looks at xf, adds `const` to it, but xf was already const by way of being a reference, so nothing special happens. Also I'm not sure why this question was marked as a duplicate. It actually seems like a slightly different question IMO. – Jon Reeves May 26 '21 at 16:45
  • Revisiting this question. If constexpr is referring to the object as explained above, why is constexpr int x=1; having type .. const int and not int? You mentioned that constexpr always refers to the object and not the type. Well in the constexpr int x=1 clearly changes the type – yapkm01 Sep 11 '21 at 22:07
  • Correct @yapkm01 it changes the type of the object `x`. So if `x` has type `int`, and `constexpr` implies `const` on the object, then `x`'s type becomes `const int`. If the object `xf` has type "reference to `int`", and `constexpr` implies `const` on the object, then `xf`'s type becomes "`const` reference to `int`" (note: **not** reference to `const int`). But all references are `const`, so this is redundant. The type change in this case adds no new information. – Jon Reeves Sep 13 '21 at 21:49