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;
}
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?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With