Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

why rvalue can't assign to constexpr reference variable

I have the following code

constexpr int into(int a,int b)
{
  int c=a*b;
  return c;
}

int main()
{
 constexpr int &n=into(5,5);

}

and I have read (in MSDN)

The keyword constexpr was introduced in C++11 and improved in C++14. It means constant expression. Like const, it can be applied to variables so that a compiler error will be raised if any code attempts to modify the value.

After I read it, I thought that constexpr can be used in place of const, but for the above code I get a compiler error stating

`int main()':
invalid initialization of non-const reference of type 'int&' from an rvalue of type 'int'`

When constexpr is replaced with const, it works fine. I don't understand this behavior; can somebody shed some light?

like image 533
RaGa__M Avatar asked Feb 25 '26 05:02

RaGa__M


2 Answers

Unlike const, which applies to int, the constexpr keyword applies const directly to the variable of reference type int&, which has no effect.

typedef int &int_ref;

int main() {
    int x = 1;
    int &a = x;          // OK
    int_ref b = x;       // OK, int_ref is 'int &'
    const int &c = 1;    // OK, reference to const int
    const int_ref d = 1; // error: type of d is 'int &'
                         // qualifier on reference are being ignored
}

constexpr int &n and constexpr int_ref n is the same, while const int &n and const int_ref n have the qualifier different.

like image 139
user1887915 Avatar answered Feb 27 '26 18:02

user1887915


Expressions marked as constexpr will be resolved at compile-time, which will treat the result of into(5,5) as an int literal. As we know, references cannot be bound to an int literal in C++.

You could make this work by making constexpr int x=into(5,5); appear at the global scope and within the main creating a constexpr const int reference to x forcing x to be resolved before main is called which then allows a reference to be bound to x:

constexpr int into(int a,int b) {
  int c=a*b;
  return c;
}

// guaranteed to be resolved before main is called
constexpr int x = into(5,5);

int main() {
 constexpr const int& n = x;
 static_assert(n == 25, "whoops!");
}

To specifically answer your question, this is completely orthogonal to rvalues or move semantics, but rather is a nuance of constexpr.

If global scoping gives you heartburn, you could make x a static as well and put its initialization before its reference binding, which seems more natural to me:

constexpr int into(int a,int b) {
  int c=a*b;
  return c;
}  

int main() {
 // guaranteed to be resolved before main is called
 static constexpr int x = into(5,5);
 constexpr const int& n = x;
 static_assert(n == 25, "whoops!");
}
like image 43
erip Avatar answered Feb 27 '26 18:02

erip