I have the following snippet which has an object with a compile-time value:
template <int V>
struct Value
{
constexpr Value() = default;
constexpr int value() const { return V; }
};
int main()
{
Value<1> v;
static_assert(v.value(), ""); // OK
auto l = [=]()
{
static_assert(v.value(), ""); // Error
};
(void)l;
}
The problem is in the static_assert
within the lambda. It passes on gcc 6.4, 10.1 but fails on 7.1 and 8.1. The first assert (outside of the lamda) passes on all of them. If changed to constexpr Value<1> v;
, it starts passing on 7.1 but not 8.1. I was wondering why this is happening.
gcc 8.1 contained a compiler bug that prevented lambda captures from being constexpr:
Bug 86429 - [8 Regression] lambda capture breaks constexpr-ness
It was fixed in 8.4, but not backported to previous versions. So gcc versions 8.1 - 8.3 still contain this bug, preventing the captured v
from being treated as constexpr.
For 7.1 i'm not 100% sure since i didn't manage to find a bug for it; but given that it rejects some constructs even with constexpr
my guess would be that it is a precursor-bug to the 8.1 one that just happend to remain unnoticed.
It fails with exactly the same error message - '__closure' is not a constant expression
- if an explicit capture clause is used:
constexpr Value<1> v;
static_assert(v.value(),""); // OK
auto l = [v]() {
static_assert(v.value(),""); // OK (Error in 7.1)
};
auto l2 = [&v]() {
static_assert(v.value(),""); // OK (Error in 7.1)
};
auto l3 = [=]() {
static_assert(v.value(),""); // OK
};
auto l4 = [&]() {
static_assert(v.value(),""); // OK
};