I had this piece of code which compiles
#include <bitset>
struct A{
std::bitset<50> b; };
void test(A a){
static_assert(sizeof(int)*8 < a.b.size(), "can't accomodate int in bitset");
int x = 5;
a.b = x; }
int main(){
A a;
test(a); }
But this doesn't
#include <bitset>
struct A{
std::bitset<50> b;
};
void test(A& a){
static_assert(sizeof(int)*8 < a.b.size(), "can't accomodate int in bitset");
int x = 5;
a.b = x;
}
int main(){
A a;
test(a);
}
Fails with this error
const.cpp: In function ‘void test(A&)’: const.cpp:8:5: error: non-constant condition for static assertion
static_assert(sizeof(int)*8 < a.b.size(), "can't accomodate int in bitset");
const.cpp:8:5: error: ‘a’ is not a constant expression
Why is a.b.size()
not treated as a constexpr in the second case? Isn't the constexpr
for std::bitset::size()
the one that should be treated as const as per the reference? Or does the non-const reference passed in the second case trigger the compiler to generate the error?
Compiler version:
g++ 4.8.4 on Ubuntu 14.0.4, compiled with g++ const.cpp -std=c++1y
Deprecation Notice |
---|
This answer is now obsolete due to the changes in P2280: Using unknown pointers and references in constant expressions (proposal accepted into C++23 and applied as a defect report to C++11). GCC 14 and more recent compilers accept the original code as valid. See https://godbolt.org/z/KE5G969ca. |
A& a
is not usable in constant expressions, making your program ill-formed.
The rule forbidding a.b.size()
to be a constant expression with a
being a A&
is the following:
[expr.const]/3
A variable is usable in constant expressions after its initializing declaration is encountered if it is a constexpr variable, or it is of reference type or of const-qualified integral or enumeration type, and its initializer is a constant initializer.
In your case, the variable a
is:
constexpr
(as a function argument, it wouldn't make sense),
[expr.const]/2
A constant initializer for a variable or temporary object
o
is an initializer for which interpreting its full-expression as a constant-expression results in a constant expression, except that ifo
is an object, such an initializer may also invoke constexpr constructors foro
and its subobjects even if those objects are of non-literal class types.
Take the following reduced example:
struct s { constexpr static bool true_value() { return true; } };
void assert_on(s const& ref)
{
static_assert(ref.true_value());
}
int main()
{
assert_on(s{});
}
gcc-9 wrongly accepts it1, but clang-8 produce the right diagnostic:
error: static_assert expression is not an integral constant expression
Full demo: https://godbolt.org/z/t_-Ubj
1) This is GCC bug #66477, active from version 5.1 and yet to be resolved.