Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Strange behavior with constexpr interacting with const references

I tested the following code with both clang and gcc (trunk versions). Can someone explain why the case with the plain X struct does not work, while both the by value capture and the wrapper case that uses const reference work just fine.

struct X {
  constexpr X(const int &v) : x(v) {}
  constexpr int Get() const { return x; }
private:
  const int& x;
};

constexpr X f(const X& r) {
  return r;
}

struct Y {
  constexpr Y(const int &v) : x(v) {}
  constexpr int Get() const { return x; }
private:
  const int x;
};

constexpr Y f(const Y& r) {
  return r;
}

struct Wrap {
  constexpr Wrap(const int& v) : x(v) {}
  constexpr Y Get() const { return Y{x}; }
private:
  const int x;
};


int main() {
  constexpr const int x = 10;

  /* this does not work for some reason 
  constexpr X a(x);
  static_assert(f(a).Get() == 10, "This should work.");
  */

  // This works.
  constexpr Y b(x);
  static_assert(f(b).Get() == 10, "This should work.");

  // This also works.
  constexpr Wrap c(x);
  static_assert(f(c.Get()).Get() == 10, "This should work.");

  return 0;
}
like image 223
Šimon Tóth Avatar asked Jan 25 '23 19:01

Šimon Tóth


1 Answers

The rule you're violating here:

constexpr X a(x);

Is that a consetxpr pointer or a constexpr reference has to refer to an object with static storage duration - that's the only way for its address to itself be a constant expression. That is not the case with x.

But once you make it so (the const was redundant):

static constexpr int x = 10;

then the rest works:

constexpr X a(x);
static_assert(f(a).Get() == 10, "This should work.");

The specific rule is [expr.const]/11:

A constant expression is either a glvalue core constant expression that refers to an entity that is a permitted result of a constant expression (as defined below), or a prvalue core constant expression whose value satisfies the following constraints:

  • if the value is an object of class type, each non-static data member of reference type refers to an entity that is a permitted result of a constant expression,

[...]

An entity is a permitted result of a constant expression if it is an object with static storage duration that either is not a temporary object or is a temporary object whose value satisfies the above constraints, or if it is a non-immediate function.


See also these answers of mine. I should probably just close all of these as dupes of one of these?

like image 104
Barry Avatar answered May 18 '23 20:05

Barry